代码之家  ›  专栏  ›  技术社区  ›  user1244932

qt::popup中断qscroller动态滚动?

  •  3
  • user1244932  · 技术社区  · 6 年前

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

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

    但是如果我把 Q表格视图 里面 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 回复  |  直到 6 年前
        1
  •  1
  •   cbuchart    6 年前

    qt不能在可滚动区域中完全实现手势,因为 explained in their own documentation :

    qt并不能很好地反映可滚动视图(继承qabstratemView的widget类、qml类)上的系统行为wrt笔势。

    […]

    在小部件中,PAN识别器目前是硬编码的,可以使用2个触摸点。对于触摸屏,应将其更改为一个。但是,如果只保留一个手指平移来选择文本,就不能这样做。

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

    另一方面,有一个 known (和) old )未定义的行为 QTouchEvents 和弹出窗口小部件:

    打开弹出窗口或在有多个活动触点的情况下抓取鼠标时,qtouchevents的行为未定义。

    也许这两个问题的结合是你问题的根源。

    作为一种可能的解决方法(虽然不是完全按照您的需要),您可以使用 QWidget::grabGesture(Qt::PanGesture) 作为替代方案。此外,正如@mohammad kanan在评论中提到的,您可以尝试 Qt::FramelessWindowHint | Qt::Tool 而不是 Qt::Popup .