在工作中使用QSerialPort+QThread时报出:QWinEventNotifier: Event notifiers cannot be enabled or disabled from another thread错误。相关代码如下:
void MainWindow::OnConnectionBtnClicked(void) // 一个按钮的槽函数
{
bool bResult = false;
m_pModbusMaster->moveToThread(m_pUartThread); // m_pModbusMaster是一个封装QSerialPort功能的类
m_pModbusMaster->m_pUart->moveToThread(m_pUartThread);// m_pUartThread是一个QThread类
bResult = m_pModbusMaster->m_pUart->Open(); // 打开串口操作,m_pUart是一个QSerialPort类
if (bResult)
{
ui->disconnectionBtn->setEnabled(true);
ui->connectionSettingBtn->setEnabled(false);
ui->connectionBtn->setEnabled(false);
}
else
{
QMessageBox::critical(this, tr("critical"), QString(tr("%1打开失败!!!")).arg(m_pModbusMaster->m_pUart->m_pPort->portName()), QMessageBox::Yes);
}
}
使用QSerialPort+QThread的目的是为了将串口的数据收发和主线程分开,从而避免主线程的卡顿。但是这段代码会报出如下错:
主要原因分析:在调用m_pModbusMaster->m_pUart->Open()打开串口之前,m_pModbusMaster、m_pUart对象已经被移动到了m_pUartThread子线程,而我的代码在主线程中进行子线程中对象的打开和关闭操作,会导致子线程对象的事件通知功能异常,所以报错。
解决方法:将m_pModbusMaster、m_pUart对象重新封装到一个新类中,在将该新类通过moveToThread方法移动到子线程中,然后通过在主线程中发送串口打开/关闭信号,子线程接收该信号并进行串口的打开和关闭操作。
新类:
class CCommunicationHandler : public QObject
{
Q_OBJECT
public:
CCommunicationHandler();
~CCommunicationHandler();
/* 通信基类 */
ModbusMaster *m_pModbusMaster;
signals:
void OpenResult(Uint32 uiComMode, bool bResult);
public slots:
void OnOpenRequestTrig(QString strSerialPortName, QSerialPort::BaudRate baudRate,
QSerialPort::Parity parity, QSerialPort::StopBits stopBits, QSerialPort::DataBits dataBits);
};
void CCommunicationHandler::OnOpenRequestTrig(QString strSerialPortName, QSerialPort::BaudRate baudRate, QSerialPort::Parity parity, QSerialPort::StopBits stopBits, QSerialPort::DataBits dataBits)
{
m_uiComMode = 0;
bool bResult = false;
if (NULL == m_pModbusMaster)
{
m_pModbusMaster = new ModbusMaster(); // 对象创建也必须在子线程中
}
bResult = m_pModbusMaster->m_pUart->Open(strSerialPortName, baudRate, parity, dataBits, stopBits);
emit OpenResult(m_uiComMode, bResult);
}
主函数中信号连接部分代码:
m_pcComHandler = new CCommunicationHandler();
m_pcComHandler->moveToThread(m_pUartThread);
m_pUartThread->start();
connect(this, SIGNAL(OpenRequest(QString, QSerialPort::BaudRate, QSerialPort::Parity, QSerialPort::StopBits, QSerialPort::DataBits)),
m_pcComHandler, SLOT(OnOpenRequestTrig(QString, QSerialPort::BaudRate, QSerialPort::Parity, QSerialPort::StopBits, QSerialPort::DataBits)));
connect(m_pcComHandler, SIGNAL(OpenResult(Uint32, bool)), this, SLOT(OnOpenResult(Uint32, bool)));
原先的问题解决,但是还会引入新的问题
这是因为没有注册QSerialPort::BaudRate、QSerialPort::Parity、 QSerialPort::StopBits、 QSerialPort::DataBits对象(但是如果只有一个主线程的话就不需要)
解决方法:只需要在main函数中加入以下代码即可
qRegisterMetaType<QSerialPort::BaudRate>("QSerialPort::BaudRate");
qRegisterMetaType<QSerialPort::Parity>("QSerialPort::Parity");
qRegisterMetaType<QSerialPort::StopBits>("QSerialPort::StopBits");
qRegisterMetaType<QSerialPort::DataBits>("QSerialPort::DataBits");