Qt :: Popup打破QScroller动能滚动?

时间:2018-05-23 14:31:28

标签: c++ linux qt qt5 touchscreen

首先,我的问题只能在带触摸屏的设备上重现, 用PC /鼠标一切正常。

如果我使用QTableView + QScroller作为独立窗口,一切正常 - 我将手指从下往上滚动,从上到下向上滚动。

但如果我将QTableView放在QWidget Qt::Popup属性中,那么滚动会改变方向!我将手指从下往上移动,然后向上滚动,从上到下向下滚动。

这是我的代码:

#include <QAbstractTableModel>
#include <QScroller>
#include <QTouchDevice>
#include <QVBoxLayout>
#include <QtDebug>
#include <QtWidgets/QApplication>
#include <QtWidgets/QTableView>

class MyModel : public QAbstractTableModel {
public:
  MyModel(QObject *parent) : QAbstractTableModel(parent) {}

  int rowCount(const QModelIndex &parent = QModelIndex()) const override {
    return 100;
  }
  int columnCount(const QModelIndex &parent = QModelIndex()) const override {
    return 3;
  }
  QVariant data(const QModelIndex &index,
                int role = Qt::DisplayRole) const override {
    if (role == Qt::DisplayRole) {
      return QString("Row%1, Column%2")
          .arg(index.row() + 1)
          .arg(index.column() + 1);
    }
    return QVariant();
  }
  QVariant headerData(int section, Qt::Orientation orientation,
                      int role) const override {
    if (role == Qt::DisplayRole) {
      if (orientation == Qt::Horizontal) {
        switch (section) {
        case 0:
          return QString("first");
        case 1:
          return QString("second");
        case 2:
          return QString("third");
        }
      }
    }
    return QVariant();
  }
};

bool is_touch_screen_avaible() {
  const auto devs = QTouchDevice::devices();
  for (const auto &dev : devs) {
    if (dev->type() == QTouchDevice::TouchScreen) {
      return true;
    }
  }
  return false;
}

void configure_scoller_for_item_view(QAbstractItemView *view) {
  QScroller *scroller = QScroller::scroller(view);
  view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
  view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
  QScrollerProperties properties =
      QScroller::scroller(scroller)->scrollerProperties();
  QVariant overshootPolicy =
      QVariant::fromValue<QScrollerProperties::OvershootPolicy>(
          QScrollerProperties::OvershootAlwaysOff);
  properties.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy,
                             overshootPolicy);
  scroller->setScrollerProperties(properties);
  properties.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy,
                             overshootPolicy);
  scroller->setScrollerProperties(properties);
  if (is_touch_screen_avaible())
    scroller->grabGesture(view, QScroller::TouchGesture);
  else
    scroller->grabGesture(view, QScroller::LeftMouseButtonGesture);
}

#define POPUP

int main(int argc, char *argv[]) {
  QApplication a(argc, argv);
#ifdef POPUP
  QWidget *mainWin = new QWidget;
  mainWin->setWindowFlags(Qt::Popup);
  auto lay = new QVBoxLayout(mainWin);
  mainWin->setLayout(lay);
  auto tableView = new QTableView(mainWin);
  lay->addWidget(tableView);
#else
  auto tableView = new QTableView;
#endif
  MyModel myModel(nullptr);
  tableView->setModel(&myModel);
  tableView->setSelectionMode(QAbstractItemView::NoSelection);
  tableView->setFocusPolicy(Qt::NoFocus);
  configure_scoller_for_item_view(tableView);

#ifdef POPUP
  mainWin->resize(500, 500);
  mainWin->show();
#else
  tableView->resize(500, 500);
  tableView->show();
#endif

  return a.exec();
}

1 个答案:

答案 0 :(得分:1)

Qt并未在可滚动区域中完全实现手势explained in their own documentation

  

Qt并没有真正反映出可滚动视图(继承QAbstractItemView,QML类的小部件类)上的手势的系统行为。

     

[...]

     

在小部件中,平移识别器目前硬编码为使用2个触摸点。对于触摸屏,应将其更改为一个。但只要保留单指平移选择文本,就无法做到这一点。

     

使用触摸屏时,小部件中的选择由系统(Windows)或Qt本身(其他平台)触摸合成的鼠标事件驱动。相同的触摸事件驱动QGestureManager。

另一方面,QTouchEvents(和known)未定义的行为带有QWidget::grabGesture(Qt::PanGesture)和弹出窗口小部件:

  

当有多个活动触摸点时,打开弹出窗口或抓取鼠标时,QTouchEvents的行为未定义。

两个问题的结合可能是问题的根源。

作为一种可能的解决方法(尽管不完全符合您的要求),您可以使用Qt::FramelessWindowHint | Qt::Tool作为替代方案启用双指滚动。另外,正如@ mohammad-kanan在评论中所提到的,您可以尝试使用Qt::Popup代替xmlns:cdv="http://cordova.apache.org/ns/1.0"

相关问题