提示:本文为学习记录,若有疑问,请联系作者,谦虚受教
前言
通过继承QAbstractNativeEventFilter接口实现串口热插拔监测功能;
通过在QWidget中重写nativeEvent实现串口热插拔监测功能;
通过一个函数获取系统中所有可用串口名;
自动添加、移除可用串口。
一、.H文件
代码如下(示例):
#ifndef COMCHANGE_H
#define COMCHANGE_H
#include <QObject>
#include <qabstractnativeeventfilter.h>
#include <windows.h>
#include "dbt.h"
class ComChange : public QObject, public QAbstractNativeEventFilter
{
Q_OBJECT
public:
static ComChange* getInstance();
static QStringList getAvailablePort();
void setHWND(HWND hwnd);
private:
explicit ComChange(QObject *parent = nullptr);
protected:
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);
signals:
/**
* @brief 传出串口热插拔状态
* @param name 串口名
* @param flag true:插入 false:拔出
*/
void comStatus(QString name, bool flag);
private:
static ComChange* m_comChange;
HWND m_hwnd;
};
#endif // COMCHANGE_H
二、.CPP
#include "comchange.h"
#include <QApplication>
#include <QMutex>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <qdebug.h>
ComChange* ComChange::m_comChange = nullptr;
ComChange *ComChange::getInstance()
{
if(m_comChange == nullptr)
{
static QMutex mutex; //实例互斥锁。
QMutexLocker locker(&mutex); //加互斥锁。
if(m_comChange == nullptr)
{
m_comChange = new ComChange();
}
}
return m_comChange;
}
/**
* @brief 获取系统中所有可用的串口名
* @return
*/
QStringList ComChange::getAvailablePort()
{
QStringList strName;
foreach(const QSerialPortInfo& info, QSerialPortInfo::availablePorts())
{
QSerialPort port(info);
if(port.open(QIODevice::ReadWrite))
{
strName << info.portName();
port.close();
}
}
return strName;
}
/**
* @brief 设置窗口句柄用于过滤事件
* @param hwnd
*/
void ComChange::setHWND(HWND hwnd)
{
this->m_hwnd = hwnd;
}
ComChange::ComChange(QObject *parent) : QObject(parent)
{
qApp->installNativeEventFilter(this); // 安装事件过滤器
}
bool ComChange::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
MSG* msg = reinterpret_cast<MSG*>(message);
if(msg->message == WM_DEVICECHANGE // 通知应用程序设备或计算机的硬件配置发生更改。
&& msg->hwnd == this->m_hwnd) // 过滤事件
{
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
switch (msg->wParam)
{
case DBT_DEVICEARRIVAL: // 插入
{
if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT) // 设备类型为串口
{
PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
QString strName = QString::fromWCharArray(lpdbv->dbcp_name); //插入的串口名
emit comStatus(strName, true);
}
break;
}
case DBT_DEVICEREMOVECOMPLETE: // 拔出
{
if (lpdb->dbch_devicetype == DBT_DEVTYP_PORT) // 设备类型为串口
{
PDEV_BROADCAST_PORT lpdbv = (PDEV_BROADCAST_PORT)lpdb;
QString strName = QString::fromWCharArray(lpdbv->dbcp_name); //拔出的串口名
emit comStatus(strName, false);
}
break;
}
default:
break;
}
}
return false;
}
三、运用
ComChange::getInstance()->setHWND(HWND)this->winId());
connect(ComChange::getInstance(),&ComChange::sig_comStatus,this,&MainWindow::Slt_comStatus);
ui.CB_COM->addItems(ComChange::getAvailablePort());
总结
善于总结,多进一步。