QSerialPort with no GUI: QObject::startTimer: Timers can only be used with threads started with QThread
-
I'm doing a DLL with no GUI (
TEMPLATE = lib
), usingQSerialPort
. I don't create threads and I don't need any: I have no GUI and having a blocking serial port operation is no problem, it is what I want.When doing:
while (!serial_uart->isWritable()); while (!serial_uart->write(frame));
I get:
QObject::startTimer: Timers can only be used with threads started with QThread
How to use
QSerialPort
in a library without GUI without triggering this error?Note: I first thought the problem was coming from
serial_uart->waitForReadyRead(timeout)
but even without this and onlyserial_uart->write()
I already have this problem. -
@JonB I'm doing a DLL lib without
QCoreApplication
. I'm really using a minimal example: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
When I call the
release/test.dll
from Python I have this: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)
Hello
QObject::startTimer: Timers can only be used with threads started with QThread
-
You need a running Q(Core)Application.
-
@Christian-Ehrlicher Thank you. Is this possible if I just want to make a small DLL without GUI?
How would you modify mytest.cpp
to do so? -
@bast236 said in QSerialPort with no GUI: QObject::startTimer: Timers can only be used with threads started with QThread:
How would you modify my test.cpp to do so?
You need to make sure a Q(Core)Application instance is available. If there is none you have to create/destroy it by yourself.
-
@Christian-Ehrlicher Is it adapted even for a simple DLL without GUI?
When looking at https://code.qt.io/cgit/qt/qtserialport.git/tree/examples/serialport/cwritersync/main.cpp?h=6.3#n59 we see it lives in amain()
with argc, argv:QCoreApplication coreApplication(argc, argv);
but for a DLL without main how would you do this?
(Also, in this code example, the variable
coreApplication
is never used later in the code). -
@bast236 said in QSerialPort with no GUI: QObject::startTimer: Timers can only be used with threads started with QThread:
without main how would you do this?
If there is none you have to create/destroy it by yourself.
Check if there is an instance, if not create one - creating and deleting an object is basic c++ stuff.
-
@Christian-Ehrlicher Yes I know how to do this, but the question is: what argc, argv to give to the
QCoreApplication
constructor? Since it's a DLL with no argc, argv, it does not make sense here.Warning: The data referred to by argc and argv must stay valid for the entire lifetime of the QCoreApplication object. In addition, argc must be greater than zero and argv must contain at least one valid character string.
Here how could I give a argument count greater than zero?
It's not a .exe file, it's a DLL, there is no argc, argv.
-
@bast236 said in QSerialPort with no GUI: QObject::startTimer: Timers can only be used with threads started with QThread:
what argc, argv to give to the QCoreApplication constructor?
argc/argv you got in your main, pass those to your DLL
-
... and make sure the argc parameter goes not out of scope as long as Q(Core)Application lives since Q(Core)Application takes this parameter as reference - otherwise Q(Core)Application will work on a dangling reference afterwards.
-
argc/argv you got in your main, pass those to your DLL
This would not really work in my context: I am coding a DLL plugin for an external .exe application that I don't create myself.
This .exe (not created by me) calls some functions of the DLL with a standardized API, and usually this pre-made API won't be made to pass the .exe's argc/argv to the DLL functions.So the only solution I see is to do a fake dummy argc/argv:
int argc = 1; const char* argv[] = { "test.exe" }; this->core_app = new QCoreApplication(argc, (char **) argv);
Do you think it is a valid solution @jsulm ?
-
@Christian-Ehrlicher said in QSerialPort with no GUI: QObject::startTimer: Timers can only be used with threads started with QThread:
You need a running Q(Core)Application.
That is not enough, unless you're only using the main thread. I want to use QSerialPort in my own std::thread and I get the same error even if I do create and exec()
QCoreApplication
on the main thread. So the error message is quite literal. I was hoping there is some workaround to not use parts of QSerialPort that need a Qt thread, but I guess there's no way and I should use another serial library instead (at which point I might as well remove Qt from the project entirely). -
@Violet-Giraffe said in QSerialPort with no GUI: QObject::startTimer: Timers can only be used with threads started with QThread:
std::thread and I get the same error
As I said you need a running event loop. Of course this event loop must be in the same thread as QSerialPort. How should it work otherwise...
-
QSerialPort should not require an event loop, that's how. It's stupid design. Or it should route through the main loop (i. e. the one in the main thread). But it is what it is, I get it.
-
@Violet-Giraffe said in QSerialPort with no GUI: QObject::startTimer: Timers can only be used with threads started with QThread:
QSerialPort should not require an event loop, that's how. It's stupid design. But it is what it is, I get it.
it doesn't that's why the "waitForXXX" functions exist. So that QSerialPort can be used in non event loop environments
-
@Violet-Giraffe please show me one framework which works without an event loop when doing async stuff. Or blocks the execution as @J-Hilk showed you.