I've encountered a following issue:
I have a GUI element class and a Thread class. I would like to exchange signals between them. However it only works in one direction. I can successfuly send a signal from main GUI window to the thread. However when I want to send a signal from the thread to the process that calls the thread, but it doesn't work. Here is how I do it:
bool GfxMapItem::mapSwitch(int seqidx)
{
...
importMapThread_ = new ImportMapThread(sequence_->item(seqidx));
connect(GUI_UI->analExportButton, SIGNAL(clicked()), importMapThread_, SLOT(interrupt1()), Qt::QueuedConnection); //<-- this one works perfectly
connect(importMapThread_, SIGNAL(progress(int)), this, SLOT(loadMap(int)), , Qt::QueuedConnection); // <-- this one unfortunatelly doesn't
...
}
The thread code is very simple and it only emits the signal (I've check that it works when I connect the thread with itself).
void ImportMapThread::run()
{
QLOGX("Running ImportMapThread...");
QLOGINC;
emit this->progress(100);
QLOGX("Stopping ImportMapThread...");
}
The thread header looks like the one below:
class ImportMapThread : public InterruptibleThread
{
Q_OBJECT
private:
...
protected:
...
public:
ImportMapThread(SeqItem *p);
signals:
void progress(int value);
void progressReset(int value);
public slots:
virtual void interrupt1();
void loadMap();
protected:
virtual void run();
};
And the class that calls that thread looks like this:
class GfxMapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
...
signals:
void mouseOutside();
void mouseMove(const QPointF &pos);
private slots:
void loadMap(int);
protected:
...
};
Any ideas? Please, I've ran out of ideas.
I believe, you should call exec in your run-implementation. Exec starts event-loop which should allow to send signals.
Take a look at:
int QThread::exec() [protected] Enters the event loop and waits until
exit() is called, returning the value that was passed to exit(). The
value returned is 0 if exit() is called via quit(). It is necessary to
call this function to start event handling.
I hope this helps.
Solved! It turned out that only the GUI elements can communicate with the threads. The thread can be inherited from other type of the thread and there isn't any problem neither with the signals nor the slots. The problem was laying in the object GfxMapItem. For some reason it just couldn't handle normal communication.
Related
I'm having some issues with Qt threading to allow the threaded part to update the GUI of my program. Seems like it's a known "problem" with Qt, so I found multiple tutorials, but I don't understand why my example here is not working.
I inherited from QThread as follow:
class CaptureThread: public QThread {
Q_OBJECT
public:
CaptureThread(const QObject *handler, QPushButton *start) {
CaptureThread::connect(start, SIGNAL(clicked()), this, SLOT(capture_loop()));
CaptureThread::connect(this, SIGNAL(sendPacket(Packet*)),
this, SLOT(receivePacket(Packet*)));
}
signals:
void sendPacket(Packet*);
public slots:
void capture_loop() {
Packet *packet;
while (my_condition) {
packet = Somewhere::getPacket();
//getPacket is define somewhere and is working fine
emit(sendPacket(packet));
std::cout << "Sending packet!" << std::endl;
}
}
};
And here is the CaptureHandler:
class CaptureHandler: public QWidget {
Q_OBJECT
public:
CaptureHandler() {
start = new QPushButton("Capture", this);
thread = new CaptureThread(this, start);
thread->start();
}
public slots:
void receivePacket(Packet *packet) {
std::cout << "Packet received!" << std::endl;
/*
Here playing with layout etc...
*/
}
private:
QPushButton *start;
CaptureThread *thread;
};
I think the signals and slots are ok, because it displays on the terminal
Sending packet!
Packet received!
Sending packet!
Packet received!
Sending packet!
Packet received!
But in the receivePacket slot, i'm trying to modify my GUI, and it does not work. The GUI just freeze, and all I can do is CTRL+C on terminal.
So i think my capture_loop, which is an infinite loop for the moment, is blocking the program, which means my thread has not started.
But I called thread->start().
I even tried to start the thread in CaptureThread constructor, by calling this->start(), but the result is the same.
Any idea?
Your using QThread wrong. By just creating the thread, it will not execute on the thread. you will need to do it inside the QThread::run function (by overriding it), since thats the only one that will run on the new thread. Please notice, that as soon as you return from this function, the thread will exit.
If you want to use your own loop inside the QThread::run function (instead using Qts default event loop), the thread won't be able to receive signals inside the run-function!
Here an example on how to use QThread:
class CaptureThread: public QThread {
Q_OBJECT
public:
CaptureThread(const QObject *handler, QPushButton *start) {
//calling "start" will automatically run the `run` function on the new thread
CaptureThread::connect(start, SIGNAL(clicked()), this, SLOT(start()));
//use queued connection, this way the slot will be executed on the handlers thread
CaptureThread::connect(this, SIGNAL(sendPacket(Packet*)),
handler, SLOT(receivePacket(Packet*)), Qt::QueuedConnection);
}
signals:
void sendPacket(Packet*);
protected:
void run() {
Packet *packet;
while (my_condition) {
packet = Somewhere::getPacket();
//getPacket is define somewhere and is working fine
emit sendPacket(packet) ;//emit is not a function
qDebug() << "Sending packet!";//you can use qDebug
}
}
};
I have simple Qt form which represents main window of my app. It has method:
void gui_popup::on_pushButton_clicked()
{
QString text = ui->MainText->toPlainText();
text = "1\n" + text;
ui->MainText->setText(text);
}
Also I have some code, running in another thread, created like this:
std:thread* core_thread = new thread(&Init); //void Init()...
Then, at some moment or condition code from std::thread need to call gui_popup::on_pushButton_clicked(). I'm trying to do it like this:
void test_callback(void* object_ptr)
{
auto this_object = (gui_popup*)object_ptr;
this_object->on_pushButton_clicked();
}
In std::thread code I'm saving test_callback pointer and gui_popup object pointer. But when it starts calling on_pushButton_clicked() program halts with segmentation fault error. This code works fine with some other simple classes, but not with QtObject. What am I doing wrong?
UPDATE:
I've solved it this way:
void test_callback(void* object_ptr)
{
QMetaObject qtmo;
qtmo.invokeMethod((gui_popup*)object_ptr, "on_pushButton_clicked");
}
it is, of course, much more complex than using QThread, emitting signals and all other suggested solutions. However thank you everyone for trying to help.
I usually solve it like this:
class Foo : public QObject
{
Q_OBJECT
Foo()
{
// connect to own signal to own slot and hence "translate" it
connect(this, SIGNAL(some_signal(QString)),
this, SLOT(some_slot(QString)));
}
signals:
void some_signal(QString s);
protected slots:
void some_slot(QString s)
{
// do something with your gui
}
public:
void callback_proxy(std::string s)
{
emit some_signal(QString::fromUtf8(m_string.c_str()));
}
};
and then the tread does not need to know about QT:
void thread_run_function(Foo* foo)
{
foo->callback_proxy("Hello from Thread!");
}
As far as I understood this is save because the connect (signal,slot) does have a additional default parameter (Qt::ConnectionType type which defaults to Qt::AutoConnection). This tells QT to dispach signals into the qt main event loop if they originate from a foreign thread. Note that using this connection type essentialy makes qt decide on runtime whether to dispatch the signal or call the slot immediately.
HtH Martin
Edits: Some more info on default parameter and this link as reference:
See http://doc.qt.io/qt-5/qt.html#ConnectionType-enum
I created an application that has a mainwindow and from this window creates a QDialog. This QDialog should create a RenderThread that emits received images from the camera or in the example emits text. When i debug this it seems that the connection is never made as adding a breakpoint in the slot CameraWindow::debugSomething does not get caught. Whats wrong ?
I followed this example: http://qt-project.org/doc/qt-4.8/threads-mandelbrot.html but it seems that i've done something wrong.
qtDEVC::qtDEVC(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
connect (ui.pushButton_startCam, SIGNAL( clicked() ),this,SLOT( startCam() ) );
/**Threading*/
CameraWindow camWindow = new CameraWindow(this);
}
int qtDEVC::startCam()
{
camWindow.show();
camWindow.startCaptureThread();
}
CameraWindow Class:
CameraWindow::CameraWindow(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
}
void CameraWindow::debugSomething(std::string something){
QString somethings(something.c_str());
qDebug()<<somethings;
}
int CameraWindow::startCaptureThread(){
RenderThread *thread = new RenderThread(this, guid, CLEYE_COLOR_RAW, CLEYE_VGA, 50);
thread->StartCapture(); //starts thread in low priority and sets _running to true
}
CameraWindow header
class CameraWindow : public QDialog
{
Q_OBJECT
public:
CameraWindow(QWidget *parent = 0);
~CameraWindow();
Ui::CameraWindow ui;
public slots:
int startCaptureThread();
void debugSomething(QString);
private:
RenderThread thread;
};
RenderThread Class
void RenderThread::run()
{
// image capturing loop
while(_running)
{
qDebug()<<("render while()"); //is printed with qdebug correctly
if (restart)
break;
if (abort)
return;
qDebug("it"); //is also printed with qdebug correctly
emit sendText(text);
}
RenderThread header
class RenderThread : public QThread
{
Q_OBJECT
public:
RenderThread(QObject *parent, GUID cameraGUID, CLEyeCameraColorMode mode, CLEyeCameraResolution resolution, float fps);
RenderThread();
~RenderThread();
bool StartCapture();
signals:
void sendText(QString &text);
protected:
void run();
private:
QMutex mutex;
QWaitCondition condition;
//some more private variables for construction
};
I think that this creation seems somehow wrong: RenderThread *thread = new RenderThread(this);
The first thing that's worrying about the question is the word "RenderThread". Note that Qt only allows rendering on the main thread. You can create separate threads for calculations of image data, but whenever you use a painter and draw objects, that must happen on the main thread. However, If you're just going to capture the image and pass that to the main thread, via signals and slots, then that should be ok.
Secondly, whilst you've not shown all your code, I'm assuming from the function called RenderThread::run() and from the Qt example that you may have inherited from QThread here. If this is the case, please note that this is not how to use QThread. Instead, you should have your class inherit from QObject and move that to a QThread. You can read about how to use QThread properly here.
I know it's a Qt example that you've followed, but even the guys at Qt think it's a bad idea. Here's an article of how to really use QThreads.
With that in mind, here's an outline of how I would use QThread for this: -
class CameraWindow : public QDialog
{
private:
CameraObject* m_pCamObject;
};
class CameraObject : public QObject
{
Q_OBJECT
public:
private slots:
startCaptureThread();
private:
};
int CameraWindow::startCaptureThread()
{
m_pCamObject = new CameraObject;
QThread* pThread = new QThread;
this->moveToThread(pThread); // CameraObject will run on the new thread
connect(pThread, SIGNAL(started()), m_pCamObject, SLOT(startCaptureThread()));
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()); // clear up when
finished
pThread->start();
}
Note that here is a CameraObject, separated from the CameraWindow. The QThread is just a controller of the thread and keeps a clean separation from the CameraObject.
Another reason for handling threads this way is that you can move multiple QObject instances to the new thread, rather than always creating a new thread per object. If you've more threads than CPU cores, you're unlikely to gain by creating yet another thread.
In the constructor of CameraWindow class, you are connecting a RenderThread's signal but it is not the same object which is started in startCaptureThread. Change your startCaptureThread like this:
int CameraWindow::startCaptureThread()
{
thread.StartCapture(); //starts thread in low priority and sets _running to true
}
In this method, the thread member of CameraWindow is started.
P.S.: post the headers too, we can't see the members from this code.
In the mentioned example, CameraWindow class holds a RenderThread thread variable, not a RenderThread *thread.
You are connecting a pointer address in your connect call:
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
Try to use a good address:
connect(thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
This is not a tested answer.
I have a class, which is an abstraction of some device.
class Device
{
public:
...
void Start();
void Stop();
void MsgLoop();
signals:
void sMsgArrived();
}
Start() and Stop() are called from GUI thread. Start() begins new thread, which runs MsgLoop(). It looks like this:
void MsgLoop()
{
forever {
if(SUCCESS == ReadMsg()) //synchronous, non-blocking
{
ProcessMsg(); //quite fast
emit sMsgArrived(); //this signal is connected with a slot in GUI thread
}
}
}
When Stop() is called, program should return from MsgLoop() and stop the thread. How can I implement this with QThread without subclassing it?
Generally you have to decide who will be responsible for managing the thread. Is it the Device or the main window? Or possibly some device manager. In your case the Device should probably manage its own thread, so if you don't want to subclass it, use composition:
class Device : QObject
{
Q_OBJECT
public:
Device(QObject * parent = NULL);
void Start();
void Stop();
private slots:
void MsgLoop();
signals:
void sMsgArrived();
private:
QThread thread;
bool stopThread;
};
Device::Device(QObject * parent) : QObject(parent)
{
moveToThread(&thread);
connect(&thread, SIGNAL(started()), this, SLOT(MsgLoop()));
}
void Device::Start()
{
stopThread = false;
thread.start();
}
void Device::Stop()
{
stopThread = true;
thread.wait(); // if you want synchronous stop
}
void Device::MsgLoop()
{
// your loop
while(!stopThread)
if(SUCCESS == ReadMsg())
{
ProcessMsg();
emit sMsgArrived();
}
QThread::currentThread->quit();
}
NOTE: the thread stopping will only work if ReadMsg really is non-blocking. If you later decide to switch to blocking read (and that would probably be appropriate for most cases), you will have to figure out another way how to stop your thread.
If you look at this link you can see that it is possible to run a method in a separate thread without subclassing a QThread.
However what you are asking is running a message loop forever.
If you follow the given example you can run your loop without subclassing but the QThread object will never enter into its own message loop cause it will never return from your slot. So here is an example but I think it would be a bad design
class Device : public QObject
{
Q_OBJECT
public:
Device(QObject* parent = 0);
~Device();
public Q_SLOTS:
void MsgLoop();
};
QThread* thread = new QThread;
Device* device = new Device;
void Widget::onBtnStartClicked()
{
device->moveToThread(thread);
//This will call start method of Device
connect(thread, SIGNAL(started()), device, SLOT(MsgLoop()));
//This will start the event loop of thread
thread->start();
}
void Widget::onBtnStopClicked()
{
//Tells the thread to exit
thread->exit(0);
}
I am afraid you have to subclass a QThread if you want to run a forever loop.
IMHO you shouldn't. Polling requires being in a forever loop. You must do this in QThread's run function so there is no way to re-implement a function without sub-classing first. Even if you were to try and workaround it with a single shot timer I don't recommend it. You are better off(this is how i like to do it) sub-classing QThread, calling moveToThread(), not call exec() and put a forever loop in run. For an example of this look at the Fortune Blocking Client example from qt. If you don't call moveToThread() on QThread then the QThread object still resides in the GUI main thread and they both share the same event loop (which is bad when using polling functions). Calling moveToThread(QThread) without calling exec() means the QThread will not have an event loop(which is good in your case). Calling exec() would start it's own event loop but is not used for polling schemes and you would leave the run function.
Boost.Signals allows various strategies of using the return values of slots to form the return value of the signal. E.g. adding them, forming a vector out of them, or returning the last one.
The common wisdom (expressed in the Qt documentation [EDIT: as well as some answers to this question ]) is that no such thing is possible with Qt signals.
However, when I run the moc on the following class definition:
class Object : public QObject {
Q_OBJECT
public:
explicit Object( QObject * parent=0 )
: QObject( parent ) {}
public Q_SLOTS:
void voidSlot();
int intSlot();
Q_SIGNALS:
void voidSignal();
int intSignal();
};
Not only doesn't moc complain about the signal with the non-void return type, it seems to actively implement it in such a way as to allow a return value to pass:
// SIGNAL 1
int Object::intSignal()
{
int _t0;
void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
return _t0;
}
So: according to the docs, this thing isn't possible. Then what is moc doing here?
Slots can have return values, so can we connect a slot with a return value to a signal with a return value now? May that be possible, after all? If so, is it useful?
EDIT: I'm not asking for workarounds, so please don't provide any.
EDIT: It obviously isn't useful in Qt::QueuedConnection mode (neither is the QPrintPreviewWidget API, though, and still it exists and is useful). But what about Qt::DirectConnection and Qt::BlockingQueuedConnection (or Qt::AutoConnection, when it resolves to Qt::DirectConnection).
OK. So, I did a little more investigating. Seems this is possible. I was able to emit a signal, and receive value from the slot the signal was connected to. But, the problem was that it only returned the last return value from the multiple connected slots:
Here's a simple class definition (main.cpp):
#include <QObject>
#include <QDebug>
class TestClass : public QObject
{
Q_OBJECT
public:
TestClass();
Q_SIGNALS:
QString testSignal();
public Q_SLOTS:
QString testSlot1() {
return QLatin1String("testSlot1");
}
QString testSlot2() {
return QLatin1String("testSlot2");
}
};
TestClass::TestClass() {
connect(this, SIGNAL(testSignal()), this, SLOT(testSlot1()));
connect(this, SIGNAL(testSignal()), this, SLOT(testSlot2()));
QString a = emit testSignal();
qDebug() << a;
}
int main() {
TestClass a;
}
#include "main.moc"
When main runs, it constructs one of the test classes. The constructor wires up two slots to the testSignal signal, and then emits the signal. It captures the return value from the slot(s) invoked.
Unfortunately, you only get the last return value. If you evaluate the code above, you'll get: "testSlot2", the last return value from the connected slots of the signal.
Here's why. Qt Signals are a syntax sugared interface to the signaling pattern. Slots are the recipients of a signal. In a direct connected signal-slot relationship, you could think of it similar to (pseudo-code):
foreach slot in connectedSlotsForSignal(signal):
value = invoke slot with parameters from signal
return value
Obviously the moc does a little more to help in this process (rudimentary type checking, etc), but this helps paint the picture.
No, they can't.
Boost::signals are quite different from those in Qt. The former provide an advanced callback mechanism, whereas the latter implement the signaling idiom. In the context of multithreading, Qt's (cross-threaded) signals depend on message queues, so they are called asynchronously at some (unknown to the emitter's thread) point in time.
Qt's qt_metacall function returns an integer status code. Because of this, I believe this makes an actual return value impossible (unless you fudge around with the meta object system and moc files after precompilation).
You do, however, have normal function parameters at your disposal. It should be possible to modify your code in such a way to use "out" parameters that act as your "return".
void ClassObj::method(return_type * return_)
{
...
if(return_) *return_ = ...;
}
// somewhere else in the code...
return_type ret;
emit this->method(&ret);
You may get a return value from Qt signal with the following code:
My example shows how to use a Qt signal to read the text of a QLineEdit.
I'm just extending what #jordan has proposed:
It should be possible to modify your code in such a way to use "out" parameters that act as your "return".
#include <QtCore>
#include <QtGui>
class SignalsRet : public QObject
{
Q_OBJECT
public:
SignalsRet()
{
connect(this, SIGNAL(Get(QString*)), SLOT(GetCurrentThread(QString*)), Qt::DirectConnection);
connect(this, SIGNAL(GetFromAnotherThread(QString*)), SLOT(ReadObject(QString*)), Qt::BlockingQueuedConnection);
edit.setText("This is a test");
}
public slots:
QString call()
{
QString text;
emit Get(&text);
return text;
}
signals:
void Get(QString *value);
void GetFromAnotherThread(QString *value);
private slots:
void GetCurrentThread(QString *value)
{
QThread *thread = QThread::currentThread();
QThread *mainthread = this->thread();
if(thread == mainthread) //Signal called from the same thread that SignalsRet class was living
ReadObject(value);
else //Signal called from another thread
emit GetFromAnotherThread(value);
}
void ReadObject(QString *value)
{
QString text = edit.text();
*value = text;
}
private:
QLineEdit edit;
};
To use this, just request call();.
You can try to workaround this with following:
All your connected slots must save their results in some place (container) accessible from signaling object
The last connected slot should somehow (select max or last value) process collected values and expose the only one
The emitting object can try to access this result
Just as an idea.