I have a problem with QThread. Let's say I want to create a class-thread what will make some calculation infinite time. And if i will send a signal, thread will stop calculation and execute something.
// Class-thread
class A: public QThread
{
protected:
void run() { exec(); }
public slots:
void calc() { while (true) {do somethning}}
void display() { display something }
}
// Class Main window
class MainWindow
{
void buttonClick() {emit signalDisplay() }
}
// main file
void main()
{
A * a = new A;
a->start();
a->calc();
MainWindow w;
connect(&w, SIGNAL(signalDisplay()), a, SLOT(display()));
w.show();
}
The problem is that if i call a->calc() it's freeze the application. But I thought that It's working sepparate? Or I miss something ?
So you use the second approach of reimplementing QThread in your class A. I think you have to put your calculation code into run() function and then just call a->start(); Add some signals like A::jobDone(bool success) etc.
When you call your a->calc() directly from main thread of course it will be executed in the thread where you called it.. in this approach only run() function is executed in another thread and this must be started with a->start(). Check the docs there is nice example..
There is also another way:
class A : public QObject {
..
public slots:
void calc();
}
void main()
{
QThread workerThread;
A * a = new A;
a->moveToThread(workerThread);
a->start();
MainWindow w;
connect(&w, SIGNAL(startProcessing()), a, SLOT(calc()));
connect(a, SIGNAL(jobFinished(QByteArray)), &w, SLOT(displayInGuiResults(QByteArray)));
emit w.startProcessing();
w.show();
}
Related
I'm making some GUI through QT.
I almost complete my work but I have a hard time dealing with Qthread.
My goal is to measure the position of the motor (it moves) and display it on the Qtextbrowser while working another function in the main thread. When I wrote codes like below, people said I can't use QTextBrowser(Qwidget) directly in the thread, so I'm searching how to return location value to the main thread. Can you do me a favor?
MDCE is a class in another header and the codes I attach are some parts of my first code.
void MotorPort::StartThread(MDCE* com, QTextBrowser* browser)
{
thread1 = QThread::create(std::bind(&MotorPort::MeasureLocation,this,com,browser));
thread1 -> start();
}
void MotorPort::MeasureLocation(MDCE* com, QTextBrowser* browser)
{
double location;
while(1)
{
location = CurrentLocation(com); \\return current position value
browser->setText(QString::number(location));
if (QThread::currentThread()->isInterruptionRequested()) return ;
}
}
void MotorPort::stopMeasure()
{
thread1->requestInterruption();
if (!thread1->wait(3000))
{
thread1->terminate();
thread1->wait();
}
thread1 = nullptr;
}
You should use the Qt signal/slot mechanism for iter-thread notification such as this. Firstly change your MotorPort class definition to declare a signal location_changed...
class MotorPort: public QObject {
Q_OBJECT;
signals:
void location_changed(QString location);
...
}
Now, rather than MotorPort::MeasureLocation invoking QTextBrowser::setText directly it should emit the location_changed signal...
void MotorPort::MeasureLocation (MDCE *com, QTextBrowser *browser)
{
while (true) {
double location = CurrentLocation(com);
/*
* Emit signal to notify of location update.
*/
emit location_changed(QString::number(location));
if (QThread::currentThread()->isInterruptionRequested())
return ;
}
}
Finally, update MotorPort::StartThread to connect the signal to the browser's setText slot...
void MotorPort::StartThread (MDCE *com, QTextBrowser *browser)
{
connect(this, &MotorPort::location_changed, browser, &QTextBrowser::setText);
thread1 = QThread::create(std::bind(&MotorPort::MeasureLocation, this, com, browser));
thread1->start();
}
I have the following worker class:
class MediaWorker : public QObject
{
Q_OBJECT
public:
explicit MediaWorker(QObject *parent = 0);
~MediaWorker();
void Exit();
signals:
void Finished();
public slots:
void OnExecuteProcess();
};
In MediaWorker.cpp
void MediaWorker::Exit()
{
emit Finished();
}
void MediaWorker::OnExecuteProcess()
{
qDebug() << "Worker Thread: " << QThread::currentThreadId();
}
In my MainWindow I do the following:
this->threadMediaWorker = new QThread();
this->mediaWorker = new MediaWorker();
this->timerMediaWorker = new QTimer();
this->timerMediaWorker->setInterval(1000);
this->timerMediaWorker->moveToThread(this->threadMediaWorker);
this->mediaWorker->moveToThread(this->threadMediaWorker);
connect(this->threadMediaWorker, SIGNAL(started()), this->timerMediaWorker, SLOT(start()));
connect(this->timerMediaWorker, &QTimer::timeout, this->mediaWorker, &MediaWorker::OnExecuteProcess);
connect(this->mediaWorker, &MediaWorker::Finished, this->threadMediaWorker, &QThread::quit);
connect(this->mediaWorker, &MediaWorker::Finished, this->mediaWorker, &MediaWorker::deleteLater);
connect(this->threadMediaWorker, &QThread::finished, this->mediaWorker, &QThread::deleteLater);
this->threadMediaWorker->start();
The threading is working properly. When I close the application I terminate the thread in the destructor:
MainWindow::~MainWindow()
{
delete ui;
this->mediaWorker->Exit();
}
so Exit() emits the Finished signal which will hopefully delete the qthread and mediaworker class.
My question is if this is the proper way of terminating both the thread and media worker class?
My question is what is the proper way of terminating both the
worker thread and media worker class?
You can just ensure that the 'media' object gets deleted while the main window gets destructed by using either QScopedPointer or std::unique_ptr.
class MainWindow : public QMainWindow {
/// ...
QThread m_workerThread;
QScopedPointer<MediaWorker> m_pMediaObject;
/// ...
};
void MainWindows::init()
{
// ... other initialization skipped ...
// for dynamic allocation of the object and keeping the track of it
m_mediaObject.reset(new MediaWorker());
m_workerThread.moveToThread(m_mediaObject.data());
}
void MainWindow::stopWorker()
{
if (m_workerThread.isRunning())
{
m_workerThread.quit(); // commands Qt thread to quit its loop
// wait till the thread actually quits
m_workerThread.wait(); // possible to specify milliseconds but
// whether or not to limit the wait is
// another question
}
}
If the worker thread used for updating the UI it makes sense to attempt to stop the worker thread before the UI objects released in
void MainWindow::closeEvent(QCloseEvent *)
{
stopWorker();
}
But there is a chance that the main window never gets closeEvent() called before the destruction so we should handle that:
MainWindow::~MainWindow()
{
stopWorker();
// it also destroys m_mediaObject
}
I'm a bit confused about how to test a QStateMachine.
I have a project well organized with source code in one side and test code on the other side.
header
class Foo
{
signals:
void sigGoToStateOne();
void sigGoToStateTwo();
void sigGoToStateThree();
private:
QStateMachine *stateMachine;
QState *state1;
QState *state2;
void initStateMachine();
}
And in the source file
Foo::initStateMachine()
{
// constructors
state1->addTransition(this,SIGNAL(sigGoToStateTwo()),this->state2);
state2->addTransition(this,SIGNAL(sigGoToStateOne()),this->state1);
}
I would like to know if there is a beautiful way to test if my stateMachine is right. In other words, how my state machine reacts if I emit sigGoToStateThree() if I'm there, etc..
Solutions i see:
1 - Get the address of stateMachine (and eventually all other states) and test it (But i don't know how)
2 - Simulate signals (sigGoToStateX()) from a test file (Again, don't know if it's possible to emit signals of my class Foo in an other class)
My unique demand is I don't want to modify the core of my source file.
Thank's in advance.
In Qt 5, signals are always public methods. To make your code compatible with Qt 4, you can make the signals explicitly public like so:
class Foo {
public:
Q_SIGNAL void sigGoToStateOne();
...
}
Alternatively, you can keep arbitrary signal visibility, and declare a friend test class:
class Foo {
friend class FooTest;
...
}
Finally, you can create a test project where you use the Qt's test framework to test the Foo class's behavior. The code below works in both Qt 4 and Qt 5.
// main.cpp
#include <QCoreApplication>
#include <QStateMachine>
#include <QEventLoop>
#include <QtTest>
#include <QTimer>
class Waiter {
QTimer m_timer;
public:
Waiter() {}
Waiter(QObject * obj, const char * signal) {
m_timer.connect(obj, signal, SIGNAL(timeout()));
}
void stop() {
m_timer.stop();
QMetaObject::invokeMethod(&m_timer, "timeout");
}
void wait(int timeout = 5000) {
QEventLoop loop;
m_timer.start(timeout);
loop.connect(&m_timer, SIGNAL(timeout()), SLOT(quit()));
loop.exec();
}
};
class SignalWaiter : public QObject, public Waiter {
Q_OBJECT
int m_count;
Q_SLOT void triggered() {
++ m_count;
stop();
}
public:
SignalWaiter(QObject * obj, const char * signal) : m_count(0) {
connect(obj, signal, SLOT(triggered()), Qt::QueuedConnection);
}
int count() const { return m_count; }
};
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
typedef QSignalSpy SignalSpy;
#else
class SignalSpy : public QSignalSpy, public Waiter {
public:
SignalSpy(QObject * obj, const char * signal) :
QSignalSpy(obj, signal), Waiter(obj, signal) {}
};
#endif
class Foo : public QObject {
Q_OBJECT
friend class FooTest;
QStateMachine m_stateMachine;
QState m_state1;
QState m_state2;
Q_SIGNAL void sigGoToStateOne();
Q_SIGNAL void sigGoToStateTwo();
public:
explicit Foo(QObject * parent = 0) :
QObject(parent),
m_state1(&m_stateMachine),
m_state2(&m_stateMachine)
{
m_stateMachine.setInitialState(&m_state1);
m_state1.addTransition(this, SIGNAL(sigGoToStateTwo()), &m_state2);
m_state2.addTransition(this, SIGNAL(sigGoToStateOne()), &m_state1);
}
Q_SLOT void start() {
m_stateMachine.start();
}
};
class FooTest : public QObject {
Q_OBJECT
void call(QObject * obj, const char * method) {
QMetaObject::invokeMethod(obj, method, Qt::QueuedConnection);
}
Q_SLOT void test1() {
// Uses QSignalSpy
Foo foo;
SignalSpy state1(&foo.m_state1, SIGNAL(entered()));
SignalSpy state2(&foo.m_state2, SIGNAL(entered()));
call(&foo, "start");
state1.wait();
QCOMPARE(state1.count(), 1);
call(&foo, "sigGoToStateTwo");
state2.wait();
QCOMPARE(state2.count(), 1);
call(&foo, "sigGoToStateOne");
state1.wait();
QCOMPARE(state1.count(), 2);
}
Q_SLOT void test2() {
// Uses SignalWaiter
Foo foo;
SignalWaiter state1(&foo.m_state1, SIGNAL(entered()));
SignalWaiter state2(&foo.m_state2, SIGNAL(entered()));
foo.start();
state1.wait();
QCOMPARE(state1.count(), 1);
emit foo.sigGoToStateTwo();
state2.wait();
QCOMPARE(state2.count(), 1);
emit foo.sigGoToStateOne();
state1.wait();
QCOMPARE(state1.count(), 2);
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
FooTest test;
QTest::qExec(&test, a.arguments());
QMetaObject::invokeMethod(&a, "quit", Qt::QueuedConnection);
return a.exec();
}
#include "main.moc"
I am forcing all signal invocations to be done from the event loop, so that the event transitions will only happen while the event loop is running. This makes the test code uniformly wait after each transition. Otherwise, the second wait would time out:
Q_SLOT void test1() {
SignalSpy state1(&m_foo.m_state1, SIGNAL(entered()));
SignalSpy state2(&m_foo.m_state2, SIGNAL(entered()));
m_foo.start();
state1.wait();
QCOMPARE(state1.count(), 1);
emit m_foo.sigGoToStateTwo(); // The state2.entered() signal is emitted here.
state2.wait(); // But we wait for it here, and this wait will time out.
QCOMPARE(state2.count(), 1); // But of course the count will match.
emit m_foo.sigGoToStateOne();
state1.wait(); // This would timeout as well.
QCOMPARE(state1.count(), 2);
}
This can be worked around without the use of explicit queued calls by the use of a signal spy class that internally uses a queued connection.
Kuba Ober gives a very good analysis of how to use the test framework & SignalSpy to do in depth testing of your state machine.
If all you're trying to do is generate a sigGoToStateX() from a test file then don't forget that you can chain signals together.
So for example given a class "Tester":
class Tester : public QObject {
Q_OBJECT
public:
Tester(Foo *fooClass) {
//Connecting signals gives you the kind of behaviour you were asking about
connect(this, SIGNAL(testTransitionToState1()), fooClass, SIGNAL(sigGoToState1()));
connect(this, SIGNAL(testTransitionToState2()), fooClass, SIGNAL(sigGoToState2()));
connect(this, SIGNAL(testTransitionToState3()), fooClass, SIGNAL(sigGoToState3()));
}
void SwitchState(int newState) {
//Now any time we emit the test signals, the foo class's signals will be emitted too!
if (newState == 1) emit testTransitionToState1();
else if (newState == 2) emit testTransitionToState1();
else if (newState == 3) emit testTransitionToState1();
}
signals:
void testTransitionToState1();
void testTransitionToState2();
void testTransitionToState3();
}
So for example calling SwitchState(1) will invoke the correct signals for switching to state 1. If this simple case is all you need for testing then that's all you really need.
If you need something more complex, go with the full SignalSpy example.
I am having a very strange problem with QObject::connect method. First please take a look at this very straightforward code:
class B : public QWidget {
Q_OBJECT
public:
explicit B(QWidget* parent = 0) : QWidget(parent) { }
signals:
void event();
}
class A : public QObject {
Q_OBJECT
public:
explicit A(QWidget* parent = 0) : QObject(parent) { b = new B(parent); init(); }
void init() { QObject::connect(b, SIGNAL(event()), this, SLOT(handler())); }
public slots:
void handler() { /*spit out some text*/ }
private:
B* b;
}
An object of A does not respond to signals emitted from object of B. I am confident that the signal is emitted as expected. The QObject::connect method return true indicating success. I ran qmake, moc and the moc_.cpp* files seems correct.
I wonder where my did I make mistake?
Edit I:
Here is the code I am working on, it is stripped down so only the relevant parts are shown:
class ListController : public QObject {
Q_OBJECT
public:
explicit ListController(Model* model, QWidget* parent = 0) : QObject(parent) { compositeView = new CompositeView(parent); initConnections(); }
void initConnections() { QObject::connect(compositeView->getListView(), SIGNAL(event()), this, SLOT(handler())); }
public slots:
void handler() { qDebug()<<"signal is received ..."; }
private:
CompositeView* view;
};
class CompositeView: public QGroupBox {
Q_OBJECT
public:
explicit CompositeView(QWidget* parent = 0) : QGroupBox(parent) { listView = new ListView(this); }
ListView* getListView() const { return listView; }
private:
ListView* listView;
};
class ListView : public QListWidget {
Q_OBJECT
public:
explicit ListView(QWidget* parent = 0) : QListWidget(parent) { }
protected:
void dropEvent(QDropEvent *event) { emit signal(); }
signals:
void signal();
};
I create a new ListController object inside a QWidget subclass passing itself as a parent and providing an appropriate Model object.
Edit II
The ListController returns CompositeView object to the main widget. the main widget adds the the composite view to its layout. At this point the parent of the CompositeView and its children is changed. Which might be the source of the problem.
The answer of this problem was way much easier than I expected.
I think I made a mistake of doing the following steps:
ListController is created on the stack.
The CompositeView object is returned and added to the main widget layout.
ListController object goes silently out of scope and gets destroyed and consequently the connection.
Comment 13 from the top was actually the solution. Thanks a lot tmpearce for your advice.
singals:
void signal();
I doubt, if it the actual code you are working, then please check the typo error.
I am trying to write an OpenGL visualization program for some scientific data using Qt. I would like to be able to use my existing program unchanged and simply be able to call the glwidget and tell it to update the data at the end of each time step. However in order to run a Qt program it appears you have to use QApplication and then qt.run() which blocks the cpu.
Here is the pseudo code
main()
{
..set up stuff
myVisualizer = new myGLWidget();
for(int i=0;i<1000;i++)
{
..do calculations
myVisualizer.update(new data)
}
}
I realize that I could put all of my existing code in to a QThread and have it send a signal whenever it is done to connect to an update. It would just be easier this way. Does anybody have an idea how to solve this?
If you really don't want to investigate the threaded solution, which would be nicer all around, you can use the special-case timeout with 0. Basically, when you run a timer with a timeout of 0, it runs the appropriate code after processing the events that are currently on the event queue. So, you could set up something like this:
class MyDialog : public QDialog
{
Q_OBJECT
public:
MyDialog()
{
m_step = 0;
QTimer::singleShot( 0, this, SLOT( Process() ) );
}
public slots:
void Process()
{
// do calculations
m_step++;
QTimer::singleShot( 0, this, SLOT( Redraw() ) );
if ( m_step != 1000 )
QTimer::singleShot( 0, this, SLOT( Process() ) );
}
void Redraw() { // do redrawing code here }
private:
int m_steps;
};
And then combine it with the Qt-proper main code:
int main( int argc, char** argv )
{
QApplication app( argc, argv );
MyDialog dialog;
dialog.show();
return ( app.exec() );
}
You can use QThread in your application and do the calculations in a seperate thread.
What you have to do is to subclass the QThread and implement the run() method.
You can create a calculator class and add some signals in that class and connect the signal to your display widget's update slot (in this case QGLWidget::updateGL()).
Here is a rough example: (All you have to is to create a thread and DisplayWidget in your main() function and set the thread's DisplayWidget.)
class Calculator: public QObject
{
Q_OBJECT
public:
Calculator();
void start();
signals:
void updateDisplayWidget(/* you can put the resulting data */);
};
class DisplayWidget(): public QGLWidget
{
Q_OBJECT
// override paint methods here
public slots:
void slotUpdateDisplayWidget(/* you can receive the resulting data*/);
};
class MyThread : public QThread
{
public:
void run();
void setDisplayWidget(DisplayWidget* displayWidget);
private:
Calculator mCalculator;
};
void MyThread::run()
{
mCalculator.start();
exec();
}
MyThread::setDisplayWidget(DisplayWidget* displayWidget)
{
displayWidget->moveToThread(this);
connect(&mCalculator, SIGNAL(updateDisplayWidget()), displayWidget, SLOT(slotUpdateDisplayWidget()));
}