Loading

QT实现串口助手中串口名的实时更新

问题及解决方案

当用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

posted @ 2024-07-03 00:11  记录学习的Lyx  阅读(17)  评论(0编辑  收藏  举报