QT實現串列埠助手中串列埠名的實時更新

记录学习的Lyx發表於2024-07-03

問題及解決方案

當用USB在電腦上插拔,自制的簡易串列埠助手中串列埠名稱不會實時更新,因此為了實現更新串列埠名,這裡記錄一下實現過程

解決方案:將Windows的裝置管理訊息傳送給QT進行處理(需要包含windows.h),自定義子類繼承QWidget、QAbstractNativeEventFilter,QAbstractNativeEventFilter類中的純虛擬函式bool nativeEventFilter()

如果使用重寫[virtual protected] bool QWidget::nativeEvent(const QByteArray &eventType, void *message, long *result),並不會接收到來的Windows的訊息,nativeEventbug。引用:https://stackoverflow.com/questions/26652783/qtnativeevent-calls

First: you don't need to call nativeEvent method directly. It is a callback that is called by Qt. You may override it.

Second. There are known bugs in Qt5 with processing nativeEvent. So be careful with it. But, as I know, there are problemd only with native child widgets.

Second. There are known bugs in Qt5 with processing nativeEvent. So be careful with it. But, as I know, there are problemd only with native child widgets.

Third. Solution: create your own QAbstractNativeEventFilter. Hint, how to use it (because it is not well-documented):

QAbstractEventDispatcher::instance()->installNativeEventFilter(yourFilter);

原始碼

myeventfilter.h的內容如下:

#ifndef MYEVENTFILTER_H
#define MYEVENTFILTER_H

#include <QAbstractNativeEventFilter>
#include <QWidget>

class MyNativeFilter : public QWidget, public QAbstractNativeEventFilter
{
    Q_OBJECT
public:
    MyNativeFilter();
    virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);
signals:
    void DeviceChanged();

};

#endif // MYEVENTFILTER_H

這裡繼承QWidget是為了使用訊號與槽機制,新增了宏Q_OBJECT需要重新Build(構建)一下專案,否則會出現錯誤:error: undefined reference to vtable for`。有關QAbstractNativeEventFilter的介紹,參照官方文件:https://doc.qt.io/qt-5/qabstractnativeeventfilter.html

myeventfilter.cpp的內容如下,必須需要包含標頭檔案windows.hdbt.h

#include "myeventfilter.h"
#include <windows.h>
#include <dbt.h>

MyNativeFilter::MyNativeFilter()
{

}

bool MyNativeFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
    Q_UNUSED(eventType);
    Q_UNUSED(result);
    MSG *msg = static_cast<MSG*>(message);
    if(msg->message == WM_DEVICECHANGE)
    {
        if(msg->wParam == DBT_DEVICEARRIVAL ||
                msg->wParam == DBT_DEVICEREMOVECOMPLETE) //新增了裝置或移除了裝置
        {
            emit DeviceChanged();	//發出裝置修改的訊號
        }

    }

    return false;
}

MSG是在winuser.h中宣告的結構體

typedef struct tagMSG {
  HWND   hwnd;
  UINT   message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD  time;
  POINT  pt;
  DWORD  lPrivate;
} MSG, *PMSG, *NPMSG, *LPMSG;

這裡只說明message和wParam兩個結構體成員

  • message:型別:UINT,訊息的識別符號。 應用程式只能使用低字;高字由系統保留。
  • wParam:型別WPARAM,關於訊息的附加資訊。 確切含義取決於訊息成員的值。

message的取值:Wm/裝置管理訊息 https://learn.microsoft.com/zh-cn/windows/win32/winmsg/about-messages-and-message-queues

wParam的取值:WM_DEVICECHANGE 訊息 (Winuser.h) - Win32 apps | Microsoft Learn

微軟官網文件:https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/ns-winuser-msg

官方文件上寫到:在重新實現此功能時,如果您想過濾掉訊息,即停止進一步處理,請返回true;否則返回false。因為這裡需要進一步處理msg,所以這裡返回false。

In your reimplementation of this function, if you want to filter the message out, i.e. stop it being handled further, return true; otherwise return false.

使用方法

自定義類SerialPortWidget,在serialportidget.cpp中實現,serialportidget.cpp部分程式碼如下:

 
#include <QCoreApplication>
#include "myeventfilter.h"		//包含事件過濾器標頭檔案


MyNativeFilter *nativefilter = new MyNativeFilter;
qApp->installNativeEventFilter(nativefilter);	//設定本地事件過濾器
												//qApp是一個宏,等價於QCoreApplication::instance()

//從MyNativeFilter類中發射出的訊號DeviceChanged,在serialportidget.cpp中進行訊號的處理
connect(nativefilter, &MyNativeFilter::DeviceChanged, [=]{
    if(serialport->isOpen())
        serialport->close();
    //獲取串列埠資訊,進行串列埠名重新整理
    QList<QSerialPortInfo> infos = QSerialPortInfo::availablePorts();
    serialPortComboBox->clear();
    for (const QSerialPortInfo &info : infos)		//foreach遍歷串列埠資訊
        serialPortComboBox->addItem(info.portName());   //獲取串列埠名
});

執行效果

參考連結:

https://stackoverflow.com/questions/26652783/qtnativeevent-calls

https://blog.csdn.net/zzzw0/article/details/104367345

https://blog.csdn.net/u010168781/article/details/105298677

相關文章