项目场景:
做了一个解析USB接口的GPS接收机报文的插件,界面如下:
由于,插件只有在整个软件打开时才会初始化,中途不会析构,那么使用过程中如果,GPS接收机拔出再插入另一接口,所有功能将失效,因为端口为自动解析的,并且是在初始化时,获取所有可用串口,如果想功能正常必须重启软件,肯定影响使用。
问题描述
基于项目背景,需要寻找一个响应USB接口拔插的事件。
解决方案:
直接在Widget类里使用nativeEvent方法即可。
GPSPositionWidget.h文件如下:
#ifndef GPSPositionWidget_H
#define GPSPositionWidget_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui {class CGPSPositionWidget;}
QT_END_NAMESPACE
class CGPSPositionWidget
{
Q_OBJECT
public:
CGPSPositionWidget(QWidget *parent = 0);
~CGPSPositionWidget();
public:
/**
* @fn Initialize
* @brief 初始化窗体
* @param
* @return
*/
void Initialize();
protected:
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;//监控Windows系统事件(硬件热插拔);
private:
Ui::CGPSPositionWidget* ui;
QSerialPort *m_pserial;
};
#endif // GPSPositionWidget_H
GPSPositionWidget.cpp如下:
#include "GPSPositionWidget.h"
#include "ui_GPSPositionWidget.h"
#include <QSerialPort>
#include <QSerialPortInfo>
#include "qdebug.h"
#include <windows.h>
#include "dbt.h"
CGPSPositionWidget::CGPSPositionWidget(QWidget *parent)
: CustomWidget(parent)
, m_pserial(NULL)
, m_bIsShowPoint(false)
, m_bIsSaveTra(false)
, m_pGPSMapEventHandler(nullptr)
{
ui = new Ui::CGPSPositionWidget();
ui->setupUi(panel);
setTitle(ConvertCharArrayToQString("GPS定位"));
Initialize();
}
CGPSPositionWidget::~CGPSPositionWidget()
{
delete ui;
ui = nullptr;
}
void CGPSPositionWidget::Initialize()
{
ui->portComboBox->clear();
ui->baudComboBox->clear();
ui->dataBitsComboBox->clear();
ui->stopBitsComboBox->clear();
ui->parityComboBox->clear();
ui->flowControlComboBox->clear();
ui->modeComboBox->clear();
//状态栏清空
ui->statusLabel->clear();
//获取计算机上所有可用串口并添加到comBox中
QList<QSerialPortInfo> infos = QSerialPortInfo::availablePorts();
if(infos.isEmpty())
{
ui->portComboBox->addItem(ConvertCharArrayToQString("无串口"));
return;
}
else
{
m_pserial = new QSerialPort;
}
foreach (QSerialPortInfo info, infos) {
ui->portComboBox->addItem(info.portName());
qDebug() << info.portName();
}
//设置三种波特率
QStringList strBaud;
strBaud<<ConvertCharArrayToQString("4800")<<ConvertCharArrayToQString("9600")<<ConvertCharArrayToQString("115200");
ui->baudComboBox->addItems(strBaud);
ui->baudComboBox->setCurrentIndex(1);
//设置四种数据位
QStringList strData;
strData<<ConvertCharArrayToQString("5")<<ConvertCharArrayToQString("6")<<ConvertCharArrayToQString("7")<<ConvertCharArrayToQString("8");
ui->dataBitsComboBox->addItems(strData);
ui->dataBitsComboBox->setCurrentIndex(3);
//设置三种停止位
QStringList strStop;
strStop<<ConvertCharArrayToQString("1")<<ConvertCharArrayToQString("1.5")<<ConvertCharArrayToQString("2");
ui->stopBitsComboBox->addItems(strStop);
ui->stopBitsComboBox->setCurrentIndex(0);
//设置五种校验位
QStringList strParity;
strParity<<ConvertCharArrayToQString("None")<<ConvertCharArrayToQString("Odd")<<ConvertCharArrayToQString("Even")<<ConvertCharArrayToQString("Mark")<<ConvertCharArrayToQString("Space");
ui->parityComboBox->addItems(strParity);
ui->parityComboBox->setCurrentIndex(0);
//设置四种流控
QStringList strFlowControl;
strFlowControl<<ConvertCharArrayToQString("None")<<ConvertCharArrayToQString("Hardware")<<ConvertCharArrayToQString("Software");
ui->flowControlComboBox->addItems(strFlowControl);
ui->flowControlComboBox->setCurrentIndex(0);
//设置三种定位模式
QStringList strMode;
strMode<<ConvertCharArrayToQString("推荐定位")<<ConvertCharArrayToQString("GPS定位")<<ConvertCharArrayToQString("北斗定位");
ui->modeComboBox->addItems(strMode);
ui->modeComboBox->setCurrentIndex(0);
}
bool CGPSPositionWidget::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;
Initialize();
ui->statusLabel->setText(ConvertCharArrayToQString("设备插入!"));
}
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;
//如果串口打开的过程中拔出先关闭串口
if (m_pserial != NULL)
{
m_pserial->close();
}
//恢复设置功能
ui->switchButton->setText(ConvertCharArrayToQString("打开串口"));
Initialize();
ui->statusLabel->setText(ConvertCharArrayToQString("设备拔出!"));
}
break;
}
default:
break;
}
}
return false;
}
注意:使用nativeEvent方法,.cpp文件里必须添加#include <windows.h>,#include "dbt.h"两个头文件。
ConvertCharArrayToQString()自定义格式转换方法。
最终效果如下: