文章目录
- 一、概述
- 二、nativeEvent 的定义
- 三、Windows 平台示例
- 三、使用nativeEvent监测设备变化
一、概述
Qt 的 nativeEvent 是一个特殊的事件处理机制,允许开发者处理操作系统级别的原生事件。通常,Qt 通过 QEvent 机制来管理事件,但有时我们需要直接处理底层的原生事件,例如 Windows 消息(Windows API)、X11 事件(Linux)、macOS 事件等。
二、nativeEvent 的定义
nativeEvent 是 QCoreApplication 和 QApplication 提供的一个虚函数:
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
virtual bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result);
#else
virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result);
#endif
该函数在 Qt 事件循环中会被调用,用于拦截操作系统原生事件。
参数解析:
- eventType:事件类型,例如 Windows 下通常是 “windows_generic_MSG” 或"windows_dispatcher_MSG"。
- message:指向操作系统事件的指针。例如,在 Windows 下,它是 MSG*。
- result:用于返回处理结果(可选)。
返回值:
- true:表示事件已被处理,不需要传递给 Qt 继续处理。
- false:表示事件未被处理,Qt 仍然会继续处理它。
三、Windows 平台示例
在 Windows 上,message 其实是 MSG*,可以用来拦截特定的 Windows 消息,比如 WM_HOTKEY(全局热键)。
#include <QApplication>
#include <QDebug>
#include <QWidget>
#include <windows.h>
class MyWidget : public QWidget {
protected:
bool nativeEvent(const QByteArray &eventType, void *message, long * result) override {
if (eventType == "windows_generic_MSG") {
MSG *msg = static_cast<MSG *>(message);
if (msg->message == WM_HOTKEY) {
qDebug() << "Hotkey Pressed!";
return true; // 表示事件已处理
}
}
return QWidget::nativeEvent(eventType, message, result);
}
public:
MyWidget() {
// 注册全局热键:Ctrl + Alt + H
RegisterHotKey((HWND)winId(), 1, MOD_CONTROL | MOD_ALT, 'H');
}
~MyWidget() {
UnregisterHotKey((HWND)winId(), 1);
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyWidget w;
w.show();
return app.exec();
}
输出结果:
三、使用nativeEvent监测设备变化
1. WM_DEVICECHANGE 的基本定义
WM_DEVICECHANGE 是 Windows 操作系统提供的一个系统消息(System Message),用于通知应用程序系统中设备(如 USB 设备、存储设备、网卡等)发生了变化。例如,当插入或移除 USB 设备时,系统会发送 WM_DEVICECHANGE 消息。
在 Windows.h 头文件中,WM_DEVICECHANGE 的定义如下:
#define WM_DEVICECHANGE 0x0219
当某个设备发生变化时,Windows 会向所有顶级窗口(包括 Qt 窗口)发送 WM_DEVICECHANGE 消息。该消息的 wParam 参数表示具体的设备变化类型,常见的值如下:
其中,DBT_DEVICEARRIVAL 和 DBT_DEVICEREMOVECOMPLETE 是最常见的,用于检测 USB 设备插拔。
2. Qt 中拦截 WM_DEVICECHANGE 事件
#include <QApplication>
#include <QWidget>
#include <QDebug>
#include <windows.h>
#include <dbt.h>
class DeviceMonitorWidget : public QWidget {
protected:
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override {
if (eventType == "windows_generic_MSG") {
MSG *msg = reinterpret_cast<MSG*>(message);
if (msg->message == WM_DEVICECHANGE) {
PDEV_BROADCAST_HDR pHdr = reinterpret_cast<PDEV_BROADCAST_HDR>(msg->lParam);
PDEV_BROADCAST_VOLUME pVolume = reinterpret_cast<PDEV_BROADCAST_VOLUME>(pHdr);
if (msg->wParam == DBT_DEVICEARRIVAL) {
if (pHdr->dbch_devicetype == DBT_DEVTYP_VOLUME) {
if (pVolume->dbcv_flags == 0) {
qDebug() << "U Disk inserted";
//获取当前系统的盘符
QFileInfoList fileList = QDir::drives();
QString strPath;
for (int i = 0; i < fileList.count(); i++) {
strPath = fileList[i].filePath();
qDebug() << "strPath:" << strPath;
const wchar_t *w_usb = reinterpret_cast<const wchar_t*>(strPath.utf16());
UINT iRet = GetDriveType(w_usb);
if (iRet == DRIVE_REMOVABLE) {
qDebug() << "it's a U Disk," << "Name:" << strPath;
}
}
}
}
} else if (msg->wParam == DBT_DEVICEREMOVECOMPLETE) {
if (pHdr->dbch_devicetype == DBT_DEVTYP_VOLUME) {
if (pVolume->dbcv_flags == 0) {
qDebug() << "Pull out the U Disk";
}
}
}
}
}
return QWidget::nativeEvent(eventType, message, result);
}
public:
DeviceMonitorWidget() {
setWindowTitle("设备监视器");
resize(300, 200);
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
DeviceMonitorWidget w;
w.show();
return app.exec();
}