即使 QTabletEvent 被接受,QWidget 的 mousePressEvent 也会被调用

Tho*_*itz 5 c++ qt mouseevent qt5

在实现了 tabletEvent(QTabletEvent *event) 和 mousePressEvent(QMouseEvent *event) 的 QWidget 派生类对象中,每次使用 TabletEvent::TabletPress 类型调用 tabletEvent 时都会调用 mousePressEvent。根据Qt 文档,这不应该发生:

事件处理程序 QWidget::tabletEvent() 接收 TabletPress、TabletRelease 和 TabletMove 事件。Qt 将首先发送一个平板电脑事件,然后如果它不被任何小部件接受,它将发送一个鼠标事件

主窗口.cpp

#include "mainwindow.h"
#include "tabletwidget.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    TabletWidget* tw = new TabletWidget(this);
    setCentralWidget(tw);
}
Run Code Online (Sandbox Code Playgroud)

平板电脑.h

#ifndef TABLETWIDGET_H
#define TABLETWIDGET_H

#include <QWidget>

class TabletWidget : public QWidget
{
    Q_OBJECT
public:
    explicit TabletWidget(QWidget *parent = 0);

protected:
    void tabletEvent(QTabletEvent *event) Q_DECL_OVERRIDE;
    void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;

signals:

public slots:
};

#endif // TABLETWIDGET_H
Run Code Online (Sandbox Code Playgroud)

平板电脑.cpp

#include "tabletwidget.h"
#include <QDebug>
#include <QTabletEvent>

TabletWidget::TabletWidget(QWidget *parent) : QWidget(parent)
{

}

void TabletWidget::tabletEvent(QTabletEvent *event)
{
    event->accept();
    qDebug() << "tabletEvent: " << event->type();
}

void TabletWidget::mousePressEvent(QMouseEvent *event)
{
    qDebug() << "mousePressEvent";
}
Run Code Online (Sandbox Code Playgroud)

如果我使用笔尖或按下 Wacom Intuos CTH-680S-DEIT 的任何按钮,生成的输出是:

tabletEvent:  92
mousePressEvent
tabletEvent:  87
tabletEvent:  87
tabletEvent:  87
tabletEvent:  87
tabletEvent:  93
Run Code Online (Sandbox Code Playgroud)

所以首先调用 tabletEvent ,即使我接受该事件, mousePressEvent 还是会被调用。接下来的每个 tabletEvent 都是 QTabletEvent::TabletMove 类型,最后一个是 QTabletEvent::TabletRelease。从Qt 文档

QEvent::TabletMove 87
QEvent::TabletPress 92
QEvent::TabletRelease 93
Run Code Online (Sandbox Code Playgroud)

我已经在 Mac OS 10.10.3 和 Windows 7 上进行了测试,结果相同。这是一个错误还是我做错了?

这是在 Qt 5.4.2 上测试的。

vic*_*ann 4

事实上,根据 Qt 文档,当平板电脑在使用时,Qt 不应该发送鼠标事件。但无论如何它似乎都会这样做(我使用的是 5.5 版本)。

解决这个问题的一种方法是重新实现- 这就是发送和的event()方法;这些函数不会发送到's 。QApplicationTabletEnterProximityTabletLeaveProximityQWidgetevent()

因此,每当应用程序捕获TabletEnterProximityTabletLeaveProximity事件时,您都可以向您发送一个信号TabletWidget以更改私有 bool 变量_deviceActive。然后,在 内部添加对每个( 和)TabletWidget的检查,以查看是否为真;仅当标志为 false 时才执行该事件。 MousePressEventMouseReleaseEvent_deviceActive

为了说明这一点,继承的TabletApplication看起来像这样:

class TabletApplication : public QApplication {
    Q_OBJECT
public:
    TabletApplication(int& argv, char** argc): QApplication(argv,argc){}
    bool event(QEvent* event){
        if (event->type() == QEvent::TabletEnterProximity || event->type() == QEvent::TabletLeaveProximity) {
            bool active = event->type() == QEvent::TabletEnterProximity? 1:0;
            emit sendTabletDevice(active);
            return true; 
        }
        return QApplication::event(event);
}
signals:
    void sendTabletActive(bool active);
};
Run Code Online (Sandbox Code Playgroud)

以及里面的附加部件tabletwidget.h

class TabletWidget : public QWidget {
// ...
public slots:
     void setTabletDeviceActive(bool active){
          _deviceActive = active;
     }
// ...
private:
     bool _deviceActive;
};
Run Code Online (Sandbox Code Playgroud)

然后检查鼠标事件内部设备是否处于活动状态:

void TabletWidget::mousePressEvent(QMouseEvent *event)
{
     if (!_deviceActive) 
         qDebug() << "mousePressEvent";
}
Run Code Online (Sandbox Code Playgroud)

当然,不要忘记将相应的信号与插槽连接起来。希望能帮助到你。

参考:Qt 平板电脑示例中的 TabletApplication