Im making a console application where Im getting user input
with std::getline() (in a while loop). Im also using QextSerialPort (inherits QIODevice). Thus
I need an event loop so I'm using QCoreApplication and calling a.exec().
The problem is getline() blocks event loop and, while it's blocked, I can't receive anything from serial port. I tried to use
QCoreApplication::processEvents() in the while(1){getline()} loop, but found that's not a good solution. Then, I tried to call
QCoreApplication::processEvents() in a QThread but it didn't
work.
Here's the code Im using:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Base *base = new Base();
Commander *commander = new Commander(base);
QObject::connect(commander, SIGNAL(end()), &a, SLOT(quit()));
QTimer::singleShot(0, commander, SLOT(run()));
return a.exec();
}
void Commander::askToConnect()
{
if(base->connect() == false){
cout << "Failed to open port." << endl;
}
}
void Commander::run{
string inputline;
askToConnect();
while(1){
QCoreApplication::processEvents(); // ???
cout << endl << "> ";
getline(cin, inputline);
// ...
}
}
How can I have a getline() (or similar method) without blocking event loop?
Yes, i got similar experiences with the ProcessEvent() method called from the main thread. The problem is that it's just put on top of the current call stack and that can have other nasty side effects like endless calling depth or re-entrance problems.
I would just add a few threads to your application to create a clean solution. Since getLine() belongs to the (console) user interface, I would keep it in the main thread and move the networking code into an extra thread but other solutions are also possible (spawning threads for all kinds of interactions and just maintaining them from the main thread).
Related
So I have a qt app running on Linux. When the app is initially launched, QSettings is constantly writing to the settings.conf file even though no changes were made to QSettings. Once a user changes any setting, it stops writing and acts like normal and only writes during changes. Our hardware does not have a power button and so never shuts off and is constantly plugged in so having QSettings constantly writing to the .conf file on start up is a problem.
I looked for timers to make sure no timer was prompting to write and there are none. Tried settings.sync(). I even set a throwaway value on start up, since after changing a value in the app after initial launch it stops writing, but that didn't work. All settings persistence is written this way and after I comment out the settings.setValue at the bottom of the code, the .conf write process works as supposed to. I have no idea why it is writing when values are set from a power button click. Thoughts?
Here is the code and flow:
void MainWindow::onNavBarButtonClicked(int buttonClickedIdAsInt)
{
//.....
case NavBarButton::POWER:
activeScreenContainer->setCurrentWidget(userScreen);
activeScreenContainer ->raise();
navBarFrame->raise();
navBarActiveContainerSeparator->hide();
logoUserScreen->show();
logoUserScreen->raise();
if(orientationSelected == appPersistence::PORTRAIT_ORIENTATION_VALUE) {
timeAndUserFrame->hide();
}
emit userLoggedOut();
}
to
connect(this, &MainWindow::userLoggedOut, musicScreenModel,
&MusicScreenModel::onUserLoggedOut);
to
void MusicScreenModel::onUserLoggedOut()
{
emit userLoggedOutTreble(currentTrebleValue);
}
to
connect(musicScreenModel, &MusicScreenModel::userLoggedOutTreble,
settingsScreenModel, &SettingsScreenModel::onUserLoggedOutTreble);
to
void SettingsScreenModel::onUserLoggedOutTreble(int trebleToStore)
{
settings.setValue(appPersistence::MUSIC_TREBLE_KEY + loggedInUser,
trebleToStore);
}
And main:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QCoreApplication::setOrganizationName("Organization");
QCoreApplication::setApplicationName("AppName");
QSettings::setPath(QSettings::Format::NativeFormat,QSettings::Scope::UserScope, "/opt/");
QSettings settings;
int fontFamilyId = QFontDatabase::addApplicationFont(":/fonts/Quicksand-Bold.ttf");
settings.setValue(fontStyle::QUICKSAND_BOLD_FAMILY_ID, fontFamilyId);
if(!settings.value(appPersistence::ORIENTATION_SELECTED_KEY).isValid()) {
settings.setValue(appPersistence::ORIENTATION_SELECTED_KEY, appPersistence::LANDSCAPE_ORIENTATION_VALUE);
}
if(true) {
DevOnlyFunctions::seedRng();
}
testBuild::setIsTestBuild(false);
MainWindow w;
w.show();
return a.exec();
}
So I finally figured out what the was going wrong. We have a timer that shows whether certain Can Bus devices are present. If they are not present we hide the icons and log out the user directly through calling the onUserLoggedOut() method and not through a connect statement. I was constantly searching for a timer and connect statement and not a direct method call nested within a switch that uses a timer.
I'm trying to use QWebPage in a shared library, which means I have to have QApplication in there to get a GUI context for it to run in. I've built my code up to get this in place, however as soon as I run qApp->exec() the Event Loop completely blocks and prevents anything else from executing. This is with the shared library being ran on OS X, I've yet to try any other platforms.
I've tried adding a QTimer in to trigger every 100msecs but that doesn't ever get called, I'd assume to the event loop blocking. I've added my QApplication setup code below. I'd assume I either need to run it in a thread, or I've missed something trivial but I'm completely unsure what.
web_lib.cpp
WebLib::WebLib(int argc, char *argv[])
{
QApplication a(argc, argv, false);
connect(&m_eventTimer, SIGNAL(timeout()), this, SLOT(handleEvents()));
m_eventTimer.start(100);
a.exec();
}
void WebLib::renderFile(QString file
{
...some connection code that's boring here
m_page = new QWebPage;
m_page->mainFrame()->load(file);
}
void WebLib::handleEvents()
{
qApp->processEvents()
}
web_lib.h
class WEBLIBSHARED_EXPORT WebLib: public QObject
{
Q_OBJECT
public:
WebLib();
WebLib(int argc, char *argv[]);
void renderFile(QString fileName);
private slots:
void handleEvents();
private:
QWebPage *m_page;
QTimer m_eventTimer;
};
main.cpp
int main(int argc, char *argv[])
{
WebLib *webLib = new webLib(argc, argv);
svgLib->renderFileFromName("somePath");
return 0;
}
As soon as I run qApp->exec() the event loop completely blocks and prevents anything else from executing.
That's correct. After you're done with your rendering, you should exit the event loop.
The timer is useless, since calling processEvents from a nonblocking slot like handleEvents simply forces the event loop to be re-entered for a short time, for no reason.
Your event loop has nothing to do. You need to make the render file request before calling a.exec(), not afterwards. In other words, you need to make the following changes:
In the WebLib constructor:
1. Remove the call to a.exec().
2. Dynamically allocate the QApplication instead of putting it on the stack. 3. Remove the timer, you don't need it.
In web_lib.cpp:
Add WebLib::run(), which will call a.exec().
In main.cpp:
After the call to renderFile(), call webLib->run().
The exec must be run in a tread. Alternatively, you can call QApplication::processEvents periodically.
I'we started experimenting with unit testing in Qt and would like to hear comments on a scenario that involves unit testing signals and slots.
Here is an example:
The code i would like to test is (m_socket is a pointer to QTcpSocket):
void CommunicationProtocol::connectToCamera()
{
m_socket->connectToHost(m_cameraIp,m_port);
}
Since that is an asynchronous call i can't test a returned value. I would however like to test if the response signal that the socket emits on a successful connection (void connected ()) is in fact emitted.
I've written the test below:
void CommunicationProtocolTest::testConnectToCammera()
{
QSignalSpy spy(communicationProtocol->m_socket, SIGNAL(connected()));
communicationProtocol->connectToCamera();
QTest::qWait(250);
QCOMPARE(spy.count(), 1);
}
My motivation was, if the response doesn't happen in 250ms, something is wrong.
However, the signal is never caught, and I can't say for sure if it's even emitted. But I've noticed that I'm not starting the event loop anywhere in the test project. In the development project, the event loop is started in main with QCoreApplication::exec().
To sum it up, when unit testing a class that depends on signals and slots, where should the
QCoreApplication a(argc, argv);
return a.exec();
be run in the test environment?
I realize this is an old thread but as I hit it and as others will, there is no answer and the answer by peter and other comments still miss the point of using QSignalSpy.
To answer you original question about "where the QCoreApplication exec function is needed", basically the answer is, it isn't. QTest and QSignalSpy already has that built in.
What you really need to do in your test case is "run" the existing event loop.
Assuming you are using Qt 5:
http://doc.qt.io/qt-5/qsignalspy.html#wait
So to modify your example to use the wait function:
void CommunicationProtocolTest::testConnectToCammera()
{
QSignalSpy spy(communicationProtocol->m_socket, SIGNAL(connected()));
communicationProtocol->connectToCamera();
// wait returns true if 1 or more signals was emitted
QCOMPARE(spy.wait(250), true);
// You can be pedantic here and double check if you want
QCOMPARE(spy.count(), 1);
}
That should give you the desired behaviour without having to create another event loop.
Good question. Main issues I've hit are (1) needing to let app do app.exec() yet still close-at-end to not block automated builds and (2) needing to ensure pending events get processed before relying on the result of signal/slot calls.
For (1), you could try commenting out the app.exec() in main(). BUT then if someone has FooWidget.exec() in their class that you're testing, it's going to block/hang. Something like this is handy to force qApp to exit:
int main(int argc, char *argv[]) {
QApplication a( argc, argv );
//prevent hanging if QMenu.exec() got called
smersh().KillAppAfterTimeout(300);
::testing::InitGoogleTest(&argc, argv);
int iReturn = RUN_ALL_TESTS();
qDebug()<<"rcode:"<<iReturn;
smersh().KillAppAfterTimeout(1);
return a.exec();
}
struct smersh {
bool KillAppAfterTimeout(int secs=10) const;
};
bool smersh::KillAppAfterTimeout(int secs) const {
QScopedPointer<QTimer> timer(new QTimer);
timer->setSingleShot(true);
bool ok = timer->connect(timer.data(),SIGNAL(timeout()),qApp,SLOT(quit()),Qt::QueuedConnection);
timer->start(secs * 1000); // N seconds timeout
timer.take()->setParent(qApp);
return ok;
}
For (2), basically you have to coerce QApplication into finishing up the queued events if you're trying to verify things like QEvents from Mouse + Keyboard have expected outcome. This FlushEvents<>() method is helpful:
template <class T=void> struct FlushEvents {
FlushEvents() {
int n = 0;
while(++n<20 && qApp->hasPendingEvents() ) {
QApplication::sendPostedEvents();
QApplication::processEvents(QEventLoop::AllEvents);
YourThread::microsec_wait(100);
}
YourThread::microsec_wait(1*1000);
} };
Usage example below.
"dialog" is instance of MyDialog.
"baz" is instance of Baz.
"dialog" has a member of type Bar.
When a Bar selects a Baz, it emits a signal;
"dialog" is connected to the signal and we need to
make sure the associated slot has gotten the message.
void Bar::select(Baz* baz) {
if( baz->isValid() ) {
m_selected << baz;
emit SelectedBaz();//<- dialog has slot for this
} }
TEST(Dialog,BarBaz) { /*<code>*/
dialog->setGeometry(1,320,400,300);
dialog->repaint();
FlushEvents<>(); // see it on screen (for debugging)
//set state of dialog that has a stacked widget
dialog->setCurrentPage(i);
qDebug()<<"on page: "
<<i; // (we don't see it yet)
FlushEvents<>(); // Now dialog is drawn on page i
dialog->GetBar()->select(baz);
FlushEvents<>(); // *** without this, the next test
// can fail sporadically.
EXPECT_TRUE( dialog->getSelected_Baz_instances()
.contains(baz) );
/*<code>*/
}
I had a similar issue with Qt::QueuedConnection (event is queued automatically if the sender and the receiver belongs to different threads). Without a proper event loop in that situation, the internal state of objects depending on event processing will not be updated. To start an event loop when running QTest, change the macro QTEST_APPLESS_MAIN at the bottom of the file to QTEST_MAIN. Then, calling qApp->processEvents() will actually process events, or you can start another event loop with QEventLoop.
QSignalSpy spy(&foo, SIGNAL(ready()));
connect(&foo, SIGNAL(ready()), &bar, SLOT(work()), Qt::QueuedConnection);
foo.emitReady();
QCOMPARE(spy.count(), 1); // QSignalSpy uses Qt::DirectConnection
QCOMPARE(bar.received, false); // bar did not receive the signal, but that is normal: there is no active event loop
qApp->processEvents(); // Manually trigger event processing ...
QCOMPARE(bar.received, true); // bar receives the signal only if QTEST_MAIN() is used
I'm new to Qt, and want to simply display a video in Qt GUI. I basically got everything figured out, except for some details handling the QThread, which is really annoying.
I reformulate my question into a simpler program, hope it will explains better
first I define this QObject class
#include <QObject>
#include <QDebug>
class myObject : public QObject
{
Q_OBJECT
public:
explicit myObject(QObject *parent = 0);
bool stop;
signals:
void finishWork();
public slots:
void dowork();
void onfinishThread();
};
myObject::myObject(QObject *parent) :
QObject(parent)
{
stop = true;
}
void myObject::dowork(){
qDebug()<<"start working!";
while(!stop){
qDebug()<<"working...";
}
emit finishWork();
qDebug()<<"finish do work!";
}
void myObject::onfinishThread(){
qDebug()<<"thread is finished!";
}
then the main function
#include <QCoreApplication>
#include <QThread>
#include <iostream>
#include <windows.h>
#include "myobject.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
myObject* myObj = new myObject();
QThread* myThread = new QThread;
myThread->connect(myObj, SIGNAL(finishWork()), SLOT(quit()));
myObj->connect(myThread, SIGNAL(started()), SLOT(dowork()));
myObj->connect(myThread, SIGNAL(finished()), SLOT(onfinishThread()));
myObj->moveToThread(myThread);
myObj->stop = false;
myThread->start();
cout<<"Press ENTER to continue....."<<endl<<endl;
cin.ignore(1);
myObj->stop = true;
Sleep(10);
if(myThread->isRunning()){
qDebug()<<"The thread is still running?!!!";
}
/*
myObj->stop = false;
Sleep(1000);
myThread->start();
myObj->stop = true;
*/
myObj->deleteLater();
myThread->deleteLater();
return a.exec();
}
As you can see, I even used cin to try let the dowork() run first, but it didn't work at all, the output is
so I'm really confused on how scheduling works for QThread...
Also, if you uncomment the part
/*
myObj->stop = false;
Sleep(1000);
myThread->start();
myObj->stop = true;
*/
the output is exactly the same! only stays a while after printing
The thread is still running?!!!
Would anyone help me with this? Thanks a lot. You may simply copy all the code and test it yourself.
-------------------------Original Question, bad explanation, please ignore....----------------------------------------
I made a videoObj Class with only one function to Query the frames, the function is defined as:
void videoObj::ProcessFrame(){
bool getframe;
qDebug()<<"get in ProcessFrame";
while(!stop_flag){
getframe = capture_.read(imgOriginal_);
if(!getframe){
qDebug()<<"Video End!";
break;
}
cv::cvtColor(imgOriginal_, imgOriginal_, CV_BGR2RGB);
QImage qimgOriginal((uchar*)imgOriginal_.data, imgOriginal_.cols, imgOriginal_.rows, imgOriginal_.step, QImage::Format_RGB888);
emit imgProcessed(qimgOriginal);
this->thread()->msleep(10);
//qDebug()<<"processing frames";
}
emit stopProcess();
qDebug()<<"Stop thread";
}
Basically above code is just query frames and whenever got one emit the
SIGNAL imgProcessed(qimgOriginal)
and whenever the stop_flag is set on, stop the while loop and emit the
SIGNAL stopProcess()
I use this class in the MainWindow Class, here is how I define the connection in the constructor:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
video_obj_ = new videoObj();
video_thread_ = new QThread;
this->connect(video_obj_, SIGNAL(imgProcessed(QImage)), SLOT(onImgProcssed(QImage))); \\this is for displaying the image
video_obj_->connect(video_thread_, SIGNAL(started()), SLOT(ProcessFrame()));
video_obj_->moveToThread(video_thread_);
video_thread_->connect(video_obj_, SIGNAL(stopProcess()), SLOT(quit()));
}
Above code works fine in frame query. The problem I don't understand is, if I set video_obj_->stop_flag on in any MainWiow member function, the ProcessFrame() in videoObj Class should emit stopProcess() signal and trigger quit() of video_thread_, and then the thread should finish, that is video_thread_->finished() is true.
However, if I do something like:
connect(video_thread_, SIGNAL(finished()), this, SLOT(onStopProcess())); //onStopProcess() see below
void MainWindow::on_btnStart_clicked()
{
video_obj_->stop_flag = 1;
this->thread()->msleep(10);
video_obj_->capture_.open(ui->lineEditVidoeAddress->text().toStdString());
//... something about videoCapture setting here, not related
video_obj_->capture_.set(CV_CAP_PROP_POS_FRAMES, 0);
video_obj_->stop_flag = 0;
this->thread()->msleep(10);
if(video_thread_->isRunning()){
qDebug()<<"The thread is still running?!!!";
}
video_thread_->start();
}
void MainWindow::onStopProcess(){
qDebug()<<"thread is finished";
}
It will give me the output:
Stop thread
The thread is still running?!!!
thread is finished
Which means triggering the quit() is not finish the thread, or quit() has not been triggered.
If I use:
video_thread_->wait(); //instead of video_thread_->wait(10);
The program will just freeze.
Is anyone can help me with this, it really confuse me about this quit() and finished()...
Thanks!
Since when you call stop_flag=1, the video_thread_ finishes the current function which is
ProcessFrame
before ProcessFrame finish, quit is called on the video_thread_ through emit stopProcess().
However, quit is different from terminate, terminate can exit the thread any time (but it is not safe), quit works with the event loop, if the thread has no eventloop, quit has no effect.
I guess before qthread execute the next event in the eventloop, it checks some flag, which can be set by quit, it the flag is set by quit, then it won't execute the next event in the eventloop. Or it can also be that a quit event is inserted into the eventloop, and the next event in the eventloop will be quit.
After stop_flag = 1, you called video_thread_->wait, that will block the video_thread_ from executing the next event in the eventloop, thus the quit will not take effect before time out, however, the nextlines which print "not finished?!!!" is executed immediately. Instead of calling video_thread->wait, if you call currentThread()->Sleep(some_enough_time), then there will be time for the video_thread_ to execute the next event and quit.
You can read the Qt documentation of QThread, wait is used with terminate to terminate a thread synchronously.
============================== The new code ================================
When you do:
myObj->connect(myThread, SIGNAL(started()), SLOT(dowork()));
The signal source is myThread, the slot also belongs to myThread, since the object "myThread" is created in the main thread, thus as a object it lives in the main thread. You can call myThread->thread() to see this, it will return the main thread instead of the new thread.
However, the started signal is emitted from the new thread namely the thread that myThread represents, thus the connection is a Qt::QueuedConnection. dowork() is posted in the event queue of main thread, and it'll be executed only after a.exec() which executes the main threads eventloop.
The same thing happens to the other 2 connect calls, all the slots will be executed in the eventloop of the main thread.
First the start is emitted from the new thread when myThread->start is called, dowork is posted in the main thread's event queue.
Nothing really happens before you call a.exec();
So the program will go ahead to cin and then set stop to true, and then print "Thread is still running?!!".
Second When a.exec() is called, the dowork is executed in the main thread and "start work" is printed. Nothing is done because the stop flag is already true, and the finishwork signal is emitted from the main thread, print "finish do work";
Third The last step the finishwork is emitted, and the quit slot is directly called. However, before the new thread can really quit, the main thread has already finished the eventqueue, because no more events are posted to the main thread. The application exits without waiting for quit() to take effect.
To test this is true, do not modify any of your code, just add after
emit finishWork();
currentThread()->sleep(1000);
you will see "thread is finished!" printed, because this make time for the new thread to emit finished(), and the onfinishThread() will be add to the main thread's eventqueue.
BTW, your way of working with thread looks like java style, which is not the standard qt way. You can read this before you work on qt thread.
This is not a scheduling issue.
That you did in your code looks like:
Create a thread.
Then this thread emits a signal that it started, run slot dowork()
start a thread.
Wait for user input
echo about thread is running
execute event loop
At point 3 thread is already running and signalled about that. Because myObj is created in main thread and not moved to any other thread (to process events there), your thread does not do anything else now, but just spins event loop. At the same time event that tells you want to run myObj's dowork() is posted on the main thread. At last then it comes to step 6 you start to execute event loop of it, and first thing it finds is event that it needs to call dowork() on myObj.
To make it clear to you how Qt threads and signal-slot connection works, I recommend you to read this article on Qt blog.
In simple to fix it, you can move your object myObj to the thread that you wan't to run.
But to make this really correct, I bet that you really want is to subclass QRunnable and (re-)implement it's run method to do the stuff you wan't in QThread, so that thread does it's job, than finished correctly, so you can join on it. Or depending on your goal you might be even better with using QtConcurrent::run(aFunction)
In short, I get following error:
QObject::connect: Cannot queue arguments of type 'cv::Mat'
(Make sure 'cv::Mat' is registered using qRegisterMetaType().)
What I'm trying to do is send a signal containing two cv::Mat images from a QThread to the main thread, so that I can display the output. There's no compile time error, but when I run the program, it gets stuck at a breakpoint in qglobal.h (inline void qt_noop() {}).
I've tried to add Q_DECLARE_METATYPE(cv::Mat) to the code, to no avail. I'm quite suck with what to do now.
code
In a QThread class:
signals:
void sndFlow(cv::Mat &leftEye, cv::Mat &rightEye);
void eyesDriver::run()
{
forever
{
flow->draw(leftEye, rightEye);
sndFlow(leftEye, rightEye);
}
}
Capturing in a QObject class:
public slots:
void recFlow(cv::Mat &leftEye, cv::Mat &rightEye);
void myClass::recFlow(cv::Mat &leftEye, cv::Mat &rightEye)
{
cv::imshow("left", leftEye);
cv::imshow("rigth", rightEye);
cv::waitKey(40);
}
In main:
Q_DECLARE_METATYPE(cv::Mat)
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qRegisterMetaType< cv::Mat >("cv::Mat");
// create objects from QThread and QObject class
QObject::connect(&qthread, SIGNAL(sndFlow(cv::Mat&,cv::Mat&)),
&qobject, SLOT(recFlow(cv::Mat&,cv::Mat&)));
qthread.start();
return a.exec();
}
Changing the signal-slot variables to QSharedPointer< cv::Mat > does not work either. Gives the same error:
QObject::connect: Cannot queue arguments of type 'QSharedPointer<cv::Mat>'
(Make sure 'QSharedPointer<cv::Mat>' is registered using qRegisterMetaType().)
WORKS
All right, it seems to work. I've move qRegisterMetaType< cv::Mat >("cv::Mat"); right before the QObject::connect call. However I still have to 'F5' past the breakpoint in qglobal.h, it works afterwards.
I might be wrong, but it seems that the location of qRegisterMetaType is not trivial.
You need to call qRegisterMetaType in addition to the macro (or instead of it, depending on your needs). This is necessary for the signals to be able to marshal your data across threads. However, it might be a wiser idea to pass by reference or smart pointer, or raw pointer if you are using the QObject hierarchy to manage the object lifetime.