Qt 5 禁用点击并按住

Qt 5 Disabling Click-and-Hold

我正在尝试解决 Qt5 应用程序中由我几年前编写的触摸屏驱动程序引起的问题。问题是我的触摸屏驱动程序生成鼠标按下事件来模拟触摸行为。这是因为在我写这篇文章时,我的团队使用的是过时的 Linux OS,它没有本地触摸驱动程序。

问题是,当我触摸 +/- 按钮(increase/decrease 滑块的滚动按钮,或者如果按住它会使其快速滚动),滑块会快速滑动 up/down 就好像我点击并按住了按钮一样。这是因为我的驱动程序使用 QApplication::postEvent() 从单独的线程分派鼠标事件,并且触摸和释放之间的延迟足够长以使其注册单击并按住类型的事件,尽管释放事件不会停止滑动。

我会重写应用程序以使用现在可用的本机触摸驱动程序,但它没有提供足够的控制来执行我的驱动程序所做的事情(我的驱动程序可以生成左、右或中鼠标事件,而本机驱动程序仅提供左)。

我尝试重写驱动程序以改用 QApplication::sendEvent(),但这导致了分段错误,我无法找出原因。

那么有没有一种方法可以禁用 QSlider 本身的“单击并按住”类型的行为?这样我仍然可以点击按钮,但它们一次只会 increase/decrease 一个滴答声?

编辑:这是我如何通过驱动程序生成“触摸”事件的示例。

void InputHandler::touchPress(TouchPoint * tp, QWidget * widget) {
    QPoint screenPos(tp->cx(), tp->cy());
    QWidget * target = widget;
    if(target == NULL) target = QApplication::widgetAt(screenPos);

    if(target != NULL) {
        QPoint local = target->mapFromGlobal(screenPos);
        QMouseEvent * press = new QMouseEvent(QEvent::MouseButtonPress, local, screenPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
        QApplication::postEvent(target, press);

        DBG(" -- touch press on: " << typeid(*widget).name());

        // Check to see if the target is a QLineEdit or QComboBox, and if so, set focus on it.
        QLineEdit * lineEdit = dynamic_cast<QLineEdit*>(target);
        QComboBox * comboBox = dynamic_cast<QComboBox*>(target);
        if(lineEdit) lineEdit->setFocus(Qt::MouseFocusReason);
        if(comboBox) comboBox->setFocus(Qt::MouseFocusReason);
    }
}

编辑 2: 所以一个同事玩弄了滑块并指出他按下了 +/- 按钮,导致它滑动,然后他点击了“重置” " 按钮我们必须重置窗体上的所有控件,滑块将重置然后继续滑动,表明触摸按下从未被释放。然后,他通常会用鼠标单击 +/- 按钮并再次重置,然后它就会停止。因此,即使日志表明我的事件触发了 mousePressEvent 和 mouseReleaseEvent 方法,它们的行为似乎与使用鼠标的行为不同。

有什么想法吗?

编辑 3: 如果有帮助,我添加了一个 eventFilter 并打印出 QSlider 收到的每个事件类型,从我第一次触摸屏幕到我释放。收到的事件是:

Mouse Press (2)
Tooltip Change (184)
Paint (12)
Mouse Move (5)
Mouse Move (5)
Mouse Release (3)

但是在发布事件之后,我在日志中收到了 QEvent::Timer 事件的垃圾邮件,当我简单地用鼠标单击而不是用触摸屏触摸滑块时不会发生这种情况。如果我随后点击其他地方、拖动滑块或使用实际鼠标单击滑块,这些计时器事件就会停止。

为什么我生成的 QMouseEvent 导致这些 QEvent::Timer 事件在我用触摸屏而不是用鼠标点击滑块时生成?

生成由 QSlider 正确处理的鼠标 press/release 事件的最小示例是:

#include <QApplication>
#include <QMainWindow>
#include <QMouseEvent>
#include <QSlider>
#include <QTimer>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QMainWindow m;
    QSlider *slider = new QSlider();
    m.setCentralWidget(slider);
    m.resize(100, 100);
    m.show();

    QTimer::singleShot(1000, [&](){
        a.postEvent(slider, new QMouseEvent(QEvent::MouseButtonPress, QPoint(50,50), m.mapToGlobal(QPoint(50,50)), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
        a.postEvent(slider, new QMouseEvent(QEvent::MouseButtonRelease, QPoint(50,50), m.mapToGlobal(QPoint(50,50)), Qt::LeftButton, Qt::NoButton, Qt::NoModifier));
    });

    return a.exec();
}

此示例在 1 秒后将滑块值减小 1 个刻度。

请注意,将 Qt::NoButton 作为按钮参数传递给 QEvent::MouseButtonRelease 事件很重要,否则滑块将继续移动到当前鼠标位置(参见 QAbstractSlider::setRepeatAction),因为QSlider 认为按钮仍被按下。我假设这种行为就是你所说的 'press-and-hold'.