I am wondering if i need to disconnect singals and slots if i destroy the signal emitting object. Here is an example:
QAudioOutput * audioOutput = new QAudioOutput(format,mainWindow);
connect(audioOutput,SIGNAL(stateChanged(QAudio::State)),this,SLOT(stateChanged(QAudio::State)));
delete audioOutput;
audioOutput = new QAudioOutput(format,mainWindow);
connect(audioOutput,SIGNAL(stateChanged(QAudio::State)),this,SLOT(stateChanged(QAudio::State)));
Will this automatically disconnect the signal from the old audioOutput, or will it lead to mem leaks or some other undefined behavior ?
Thank you in advance.
The signals are automatically disconnected when you call the QObject destructor.
Have a look at the Qt documentation: QObject Destructor
You don't have to manually disconnect() signals and slots, the QObject destruction cleans them up automatically.
Related
In my project, I want to call a variable QImage image generated in the mainwindow.h, in other class files, e.g., called SegSetupDialog.h. Here the image is loaded by clicking a pushbutton in mainwindow.ui, and the SegSetupDialog is a QDialog, which pops up by clicking one pushbutton in mainwindow.ui.
I tried to use a signal-slot connection to send qimage of mainwindow to SegSetupDialog as follows.
For Class MainWindow:
SegSetupDialog *segsetup;
if(image.isNull()==false)
{
emit sendImgData(image);
qDebug()<<"sendImgData emitted!";
if(segsetup==NULL) segsetup = new SegSetupDialog();
connect(this, SIGNAL(sendImgData(QImage)),segsetup,SLOT(getImgData(QImage)),Qt::QueuedConnection);
}
In SegSetupDialog::getImgData
void SegSetupDialog::getImgData(QImage qimage)
{
qImg = qimage;
qDebug()<<"qimage received!";
}
The above connection seems not to work since the qDebug message in getImgData is not printed out. Anyone can help check something wrong with codes, or suggest other methods for accessing image of mainwindow? Thanks!!
You need to do the signal/slot connection before you emit the signal. Connections are done once, usually in the constructor.
However, you should probably do the connect() in the constructor of SegSetupDialog instead of the MainWindow one. It's SegSetupDialog that wants to be notified about image data updates, so you should establish the connection there.
Also, to make sure the signals and slots are specified correctly, don't use Qt 4 connect() calls. Use Qt 5 ones that are checked at compile-time:
connect(this, &MainWindow::sendImgData,
segsetup, &SegSetupDialog::getImgData, Qt::QueuedConnection);
(Of course change it appropriately if you move it to the SegSetupDialog constructor.)
When I use Q_PROPERTY in other QThread I have error: Illegal attempt to connect to ... that is in a different thread than the QML engine.
//myclass.cpp
Q_PROPERTY(QString FileReady READ GetFileReady NOTIFY FileReadyChanged)
This is in other QThread.
In main thread I have QtQuick2ApplicationViewer and o Connect Q_PROPERTY like that:
//main.cpp
MyClass cObject1();
QThread cThread1; //create new thread
cObject1.DoSetup(cThread1); //connect
cObject1.moveToThread(&cThread1); //move work to other thread
viewer.rootContext()->setContextProperty("otherthread",&cObject); // propably bad line
How could I send property from myclass in other thread to QML in main thread ?
If you could, give a small example how to do it.
Create class "Model" which object will stay in main thread and connect it with QML.
Create "Worker" class which do what you want to do in other thread and send updates from object of this class to object of "Model" class (default connection should do the trick).
In other directions "Model" should schedule tasks for "Worker".
This way you will keep threads away form QML engine.
I created a qt class only to make gui and displayed the data on gui.
i didn't want to freeze the gui that's why i created another non_qt class to perform the operation so i made a object in the gui class of non_qt class and pass the parameter in that and started it in a new thread.
now after completing the operation i want to notify the gui class so it can display the results.
i also want to access the status bar of gui class so when non_qt class is performing the operation it can display some message on gui..
(i tried it with qt class but it didn't work that's why i created non_qt class..with non_qt class threading part is working fine but signal part is not working so i'm not able to notify the gui class).
so please help me out how to send signal to a qt class from a not qt class????
The signal is a concept that only applies to classes that derive from QObject.
If you want to trigger a slot, you don't need a signal. If the receiving object lives in the same thread (and only then), you can call the slot method on the reciving object directly.
For example, given an instance of a GUI object with a slot:
MainWindow * mainWindow;
class MainWindow : public QWidget {
Q_OBJECT
...
Q_SLOT void setStatus(const QString &);
...
};
You can simply do:
// The assert is essential to prevent bad bugs. If it triggers,
// you must use `QMetaObject::invokeMethod` instead.
Q_ASSERT(mainWindow->thread() == QThread::currentThread());
mainWindow->setStatus("Finished");
If the receiving object may live in another thread, or if you don't want to worry about threading issues, then you must use QMetaObject::invokeMethod, as follows:
// This is always safe. No need for asserts.
QMetaObject::invokeMethod(mainWindow, "setStatus",
Q_ARG(QString, "Finished"));
This overload of invokeMethod will correctly choose the connection type depending on whether the receiving object runs in the same thread. If the receiver is in the same thread, the call is a direct call. If it runs in another thread, the call will be converted to a QMetaCallEvent and posted to the receving object. This is thread-safe and doesn't require the receving object's setStatus method to be thread-safe.
I have a subclass of QObject referred to as myObject, which has a QTimer data member allocated on the heap in the constructor. myObject also has a slot which is connected to the QTimer timeout() signal in the constructor. I refer to the pointer of myObject as myObject_ptr.
I want to run myObject on a different thread from the main thread. Following the relatively new recommendations, I DO NOT subclass QThread. In the main thread, I use myObject as follows:
QThread *thread = new QThread(this);
myObject_ptr->moveToThread(thread);
connect(myObject_ptr, SIGNAL(destroyed(), thread, SLOT(quit())); //thread not needed if no object
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); //to avoid memory leak
connect(thread, SIGNAL(terminated()), thread, SLOT(deleteLater())); //to avoid memory leak
thread->start();
The main thread invokes a function of myObject_ptr which in turn starts the QTimer data member. When it times out, nothing happens, but I expect the slot of myObject to which the timer's timeout() signal is connected to be invoked. What is the problem? How do you make this work. It works flawlessly if myObject is run on the same thread where it was created i.e. main thread.
From all the readings I've done, I think the new thread I am creating might not be processing events because it doesn't have it's own event loop. I also read documentation/articles contrary to that, saying that when the thread starts, the run() function calls exec() and you have an event loop.
Could someone help me please?
I could probably get it to work correctly if I subclass QThread, but based on current recommendations, I would prefer to avoid doing that.
Thank you in advance.
I solved my problem!! In the constructor of MyObject, the timer is allocated on the heap as follows:
timer_ptr = new QTimer(this);
but to work correctly, it should be:
timer_ptr = new QTimer(0);
and in the destructor, delete the object manually:
timer_ptr->deleteLater();
I guess when they say can't move an object with a parent to a thread, they really do mean ALL objects, including data members of the object actually being moved to the new thread.
Happy coding.
I wanted to create QObject (object) with the child QThread (thread) with that object as parent (for keeping thread alive while object is alive) and make object.moveToThread(thread) but signal to start the thread isn't working in this case.
Simply:
object owns thread
object moves to thread
signal starting thread isn't working
What's going on?
[Edit]: Throwing away my initial answer due to the comments
Maybe do it like the following:
Create the Object
Create the Thread, but don't assign a parent to it
Connect the Thread's finished() signal to its deleteLater() slot as usual
Connect the Object's deleted() signal to the thread's stop() slot
Then, when you delete the Object, it will emit deleted() which will stop the thread. The thread will emit finished() which will call its deleteLater() slot.