簡體   English   中英

沒有 GUI,沒有線程的 QSerialPort:QObject::startTimer:定時器只能用於以 QThread 啟動的線程

[英]QSerialPort with no GUI, no thread: QObject::startTimer: Timers can only be used with threads started with QThread

我正在使用 QSerialPort 做一個沒有 GUI ( TEMPLATE = lib ) 的QSerialPort 我不創建線程,也不需要任何線程:我沒有 GUI,阻塞串行端口操作沒問題,這就是我想要的。

做的時候:

while (!serial_uart->isWritable());
while (!serial_uart->write(frame));

我得到:

QObject::startTimer:定時器只能用於以 QThread 啟動的線程

問題:如何在沒有 GUI 的庫中使用QSerialPort而不會觸發此錯誤?

注意:我首先認為問題來自serial_uart->waitForReadyRead(timeout)但即使沒有這個並且只有serial_uart->write()我已經遇到了這個問題。


最小可重現 DLL 示例:

test.cpp

#include "test.h"
extern "C" {
    __declspec(dllexport) Test* new_Test() { return new Test(); }
    __declspec(dllexport) void DoTest(Test *t) { t->DoTest(); }
}
Test::Test() :QObject()
{
    qDebug("Hello");
}
void Test::DoTest()
{
    this->serialport = new QSerialPort();
    this->serialport ->setPortName("COM12");
    this->serialport->setBaudRate(QSerialPort::Baud19200);
    this->serialport->open(QIODevice::ReadWrite);
    while (!this->serialport->isWritable());
    while (!this->serialport->write("hello"));
}

test.h

#include <QSerialPort>
class Test : public QObject
{
    Q_OBJECT
public:
    Test();
    void DoTest();
    QSerialPort *serialport;
};

test.pro

TEMPLATE = lib
TARGET = test
QT += serialport
INCLUDEPATH += .
HEADERS += test.h
SOURCES += test.cpp

當我從 Python 調用release/test.dll時,我有這個:

from ctypes import *
dll = CDLL(r"release\test.dll")
dll.new_Test.restype = c_void_p
dll.new_Test.argtypes = []
dll.DoTest.restype = None
dll.DoTest.argtypes = [c_void_p]
t = dll.new_Test()
dll.DoTest(t)

你好

QObject::startTimer:定時器只能用於以 QThread 啟動的線程

Most of the QIODevice based classes (like Qt sockets or serial port) want to live in a Qt based thread and also their functions needs to be called from the same thread where the object was created.

出於這個原因,我通常通過以下方式解決這個問題:

  1. 為您將要使用的基於 QIODevice 的 class 創建包裝器 class(QObject 基於 Q_OBJECT 宏以實現信號/插槽功能)。 對於每個 function,您計划在包裝器 class 上使用創建插槽 function,然后調用 QIODevice 中的等效函數:

     qint64 MySerialPort::write(const QByteArray &data) { // m_serialPort is created with new QSerialPort in constructor of MySerialPort. return m_serialPort->write(data); }
  2. 創建一個 QThread class,在其運行 function 中創建一個 MySerialPort 實例(帶有新的 MySerialPort),然后調用 exec()。 現在 MySerialPort 生活在一個事件循環中,並且能夠發送和接收信號/插槽。

     void MySerialPortThread::run() { m_serialPort = new MySerialPort(); exec(); delete m_serialPort; // Automatic deletion after thread is stopped. }

線程還可以返回一個指向實例的指針,以便更容易地從外部訪問以連接信號和插槽。

MySerialPort* MySerialPortThread::serialPort()
{
    return m_serialPort; // Instance of  MySerialPort class
}
  1. 在您的主代碼中創建與 MySerialPort 的插槽匹配的信號並連接它們。

     signals: qint64 writeSerial(const QByteArray& data); void MyMainClass::connectSignalsAndSlots() { MySerialPort* serialPort = m_serialThread->serialPort(); connect(this, &MyMainClass::writeSerial, serialPort, &MySerialPort::write, Qt::BlockingQueuedConnection); // Use either QueuedConnection or BlockingQueuedConnection to force the execution of the slot to the MySerialThread. }
  2. 發出信號以訪問 QSerialPort。

     emit writeSerial(dataByteArray);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM