即使 QTabletEvent 被接受,QWidget 的 mousePressEvent 也会被调用
mousePressEvent of QWidget gets called even though QTabletEvent was accepted
在 QWidget 派生的 class 对象中实现了 tabletEvent(QTabletEvent *event) 和 mousePressEvent(QMouseEvent *event),每次调用类型 TabletEvent::TabletPress 的 tabletEvent 时都会调用 mousePressEvent。根据 Qt documentation,这不应该发生:
The event handler QWidget::tabletEvent() receives TabletPress, TabletRelease and TabletMove events. Qt will first send a tablet event, then if it is not accepted by any widget, it will send a mouse event.
mainwindow.cpp
#include "mainwindow.h"
#include "tabletwidget.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
TabletWidget* tw = new TabletWidget(this);
setCentralWidget(tw);
}
tabletwidget.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
tabletwidget.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";
}
如果我使用笔尖或按 Wacom Intuos CTH-680S-DEIT 的任意按钮生成的输出是:
tabletEvent: 92
mousePressEvent
tabletEvent: 87
tabletEvent: 87
tabletEvent: 87
tabletEvent: 87
tabletEvent: 93
所以首先调用 tabletEvent,即使我接受了事件,mousePressEvent 仍然被调用。接下来的每个 tabletEvent 都是 QTabletEvent::TabletMove 类型,最后一个是 QTabletEvent::TabletRelease。来自 Qt documentation:
QEvent::TabletMove 87
QEvent::TabletPress 92
QEvent::TabletRelease 93
我在 Mac OS 10.10.3 和 Windows 7 上测试过,结果相同。这是一个错误还是我做错了?
这是在 Qt 5.4.2 上测试的。
确实,根据 Qt 文档,Qt 不应在使用平板电脑时发送鼠标事件。但它似乎无论如何都可以(我使用的是 5.5 版)。
绕过它的一种方法是重新实现 QApplication
的 event()
方法 - 这是发送 TabletEnterProximity
和 TabletLeaveProximity
的地方;这些功能不会发送到 QWidget
的 event()
。
因此,每当应用程序捕捉到 TabletEnterProximity
或 TabletLeaveProximity
事件时,您可以向 TabletWidget
发送信号以更改私有 bool 变量 _deviceActive
。然后,在 TabletWidget
中,为每个 MousePressEvent
(和 MouseReleaseEvent
)添加一个检查,以查看 _deviceActive
是否为真;并且仅当标志为 false 时才执行事件。
为了说明,继承的 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);
};
以及tabletwidget.h
里面的附加部分:
class TabletWidget : public QWidget {
// ...
public slots:
void setTabletDeviceActive(bool active){
_deviceActive = active;
}
// ...
private:
bool _deviceActive;
};
然后在设备处于活动状态时检查鼠标事件:
void TabletWidget::mousePressEvent(QMouseEvent *event)
{
if (!_deviceActive)
qDebug() << "mousePressEvent";
}
当然不要忘记将相应的信号与插槽相连。希望对你有帮助。
在 QWidget 派生的 class 对象中实现了 tabletEvent(QTabletEvent *event) 和 mousePressEvent(QMouseEvent *event),每次调用类型 TabletEvent::TabletPress 的 tabletEvent 时都会调用 mousePressEvent。根据 Qt documentation,这不应该发生:
The event handler QWidget::tabletEvent() receives TabletPress, TabletRelease and TabletMove events. Qt will first send a tablet event, then if it is not accepted by any widget, it will send a mouse event.
mainwindow.cpp
#include "mainwindow.h"
#include "tabletwidget.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
TabletWidget* tw = new TabletWidget(this);
setCentralWidget(tw);
}
tabletwidget.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
tabletwidget.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";
}
如果我使用笔尖或按 Wacom Intuos CTH-680S-DEIT 的任意按钮生成的输出是:
tabletEvent: 92
mousePressEvent
tabletEvent: 87
tabletEvent: 87
tabletEvent: 87
tabletEvent: 87
tabletEvent: 93
所以首先调用 tabletEvent,即使我接受了事件,mousePressEvent 仍然被调用。接下来的每个 tabletEvent 都是 QTabletEvent::TabletMove 类型,最后一个是 QTabletEvent::TabletRelease。来自 Qt documentation:
QEvent::TabletMove 87
QEvent::TabletPress 92
QEvent::TabletRelease 93
我在 Mac OS 10.10.3 和 Windows 7 上测试过,结果相同。这是一个错误还是我做错了?
这是在 Qt 5.4.2 上测试的。
确实,根据 Qt 文档,Qt 不应在使用平板电脑时发送鼠标事件。但它似乎无论如何都可以(我使用的是 5.5 版)。
绕过它的一种方法是重新实现 QApplication
的 event()
方法 - 这是发送 TabletEnterProximity
和 TabletLeaveProximity
的地方;这些功能不会发送到 QWidget
的 event()
。
因此,每当应用程序捕捉到 TabletEnterProximity
或 TabletLeaveProximity
事件时,您可以向 TabletWidget
发送信号以更改私有 bool 变量 _deviceActive
。然后,在 TabletWidget
中,为每个 MousePressEvent
(和 MouseReleaseEvent
)添加一个检查,以查看 _deviceActive
是否为真;并且仅当标志为 false 时才执行事件。
为了说明,继承的 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);
};
以及tabletwidget.h
里面的附加部分:
class TabletWidget : public QWidget {
// ...
public slots:
void setTabletDeviceActive(bool active){
_deviceActive = active;
}
// ...
private:
bool _deviceActive;
};
然后在设备处于活动状态时检查鼠标事件:
void TabletWidget::mousePressEvent(QMouseEvent *event)
{
if (!_deviceActive)
qDebug() << "mousePressEvent";
}
当然不要忘记将相应的信号与插槽相连。希望对你有帮助。