更多精彩内容 |
---|
?个人内容分类汇总 ? |
1、主要功能
- 通过继承QAbstractNativeEventFilter接口实现串口热插拔监测功能;
- 通过在QWidget中重写nativeEvent实现串口热插拔监测功能;
- 通过一个函数获取系统中所有可用串口名;
- 自动添加、移除可用串口。
2、适用系统
3、源码地址
4、实现效果
5、实现代码
- comchange.h
/******************************************************************************
* @文件名 comchange.h
* @功能 通过继承于QAbstractNativeEventFilter来监测串口热插拔由于windows消息会发给每一个窗口,
* 所以如果打开多个窗或者使用到如QComboBox之类的控件,当串口插入或者拔出时会触发多次事件,
* 在这里我使用的解决方法时传入一个窗口句柄,通过窗口句柄过滤事件,但不知道有没有其它更好的办法。
*
* @开发者 (作者)
* @时间 2021/11/15
* @备注
*****************************************************************************/
#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
- comchange.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;
}
- widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
void on_comStatus(QString name, bool flag);
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
- widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <windows.h>
#include "dbt.h"
#include "comchange.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 第二种方法
ComChange::getInstance()->setHWND((HWND)this->winId());
connect(ComChange::getInstance(), &ComChange::comStatus, this, &Widget::on_comStatus);
ui->comboBox->addItems(ComChange::getAvailablePort());
}
Widget::~Widget()
{
delete ui;
}
/**
* @brief 第一种方法
* @param eventType
* @param message
* @param result
* @return
*/
bool Widget::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
MSG* msg = reinterpret_cast<MSG*>(message);
if(msg->message == WM_DEVICECHANGE) // 通知应用程序设备或计算机的硬件配置发生更改。
{
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); //插入的串口名
qDebug() << strName;
}
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); //拔出的串口名
qDebug() << strName;
}
break;
}
default:
break;
}
}
return false;
}
void Widget::on_comStatus(QString name, bool flag)
{
if(flag)
{
ui->comboBox->addItem(name);
}
else
{
ui->comboBox->removeItem(ui->comboBox->findText(name));
}
}
版权声明:本文为qq_43627907原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。