Qt :: Popup нарушает кинетическую прокрутку QScroller? - PullRequest
0 голосов
/ 23 мая 2018

Прежде всего, моя проблема воспроизводима только на устройстве с сенсорным экраном, с ПК / мышью все работает нормально.

Проблема в том, что если я использую 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 голосов
/ 31 мая 2018

Qt не полностью реализует жесты в прокручиваемых областях, как объяснено в их собственной документации :

Qt действительно не отражает поведение системы по отношению к жестам на прокручиваемых представлениях (виджетклассы, наследующие QAbstractItemView, классы QML).

[...]

В виджетах средство распознавания панорамы в настоящее время жестко запрограммировано для использования 2 точек касания.Для сенсорных экранов его следует изменить на один.Но этого нельзя сделать, если для выделения текста зарезервировано панорамирование одним пальцем.

При использовании сенсорного экрана выбор в виджетах определяется событиями мыши, синтезируемыми системой от прикосновения (Windows) или сам Qt (другие платформы).Те же сенсорные события приводят в действие QGestureManager.

С другой стороны, существует известное old ) неопределенное поведение с QTouchEvents и pop-вверх виджетов:

Поведение QTouchEvents не определено при открытии всплывающего окна или захвате мыши, когда имеется более одной активной точки касания.

Вероятно, комбинацияобе проблемы являются источником вашей проблемы.

В качестве возможного обходного пути (хотя и не совсем того, что вы хотите), вы можете включить прокрутку двумя пальцами с помощью QWidget::grabGesture(Qt::PanGesture) в качестве альтернативы.Также, как упомянул в своем комментарии @ mohammad-kanan, вы можете попробовать использовать Qt::FramelessWindowHint | Qt::Tool вместо Qt::Popup.

...