I have created Qt tree control( and its nodes ) in different thread than the main thread. In the main thread I want to show context menu for the clicked node, so I am connectiong the actions in the menu with appropriate slots in the main thread. The connect function returns true , but slot is never executed. If I explicitly say in connect function that this is Qt :: DirectConnection then everything works fine. Why is this ?
I I create my tree in main thread, everything also works fine , without having to say that this is Qt::DirectConnection .
See the documentation here.
The default connection type, Qt::AutoConnection, is the same as Qt::DirectConnection if the signal is sent from the same thread as the receiver slot, otherwise the behaviour is the same as Qt::QueuedConnection.
In the case where you create the widget in the main thread, you basically get the same behaviour as when you explicitly specify Qt::DirectConnection.
The behaviour of Qt::QueuedConnection is to call the slot when that threads event loop regains control.
To solve your problem, make sure you have an event loop in every thread which may be receiving signals, unless you manually specify Qt::DirectConnection (which, I assume, will mean the slot is called from the same thread as the signals emitter - basically the equivelent of a normal function call).
Related
I'm programmatically changing the selected item with setCurrentIndex() of my Tree- and TableViews.
If the current item has changed, a multitude of signals are emitted (currentChanged(), currentColumnChanged, etc).
I'm listening to some of these signals in order to be informed when the user changes the selection.
Is there a way/a signal to distinguish between user-selected and programmatically selected events?
I tried using the activated()-signal on the views, but this seems to not behave the same way on different platforms (sometimes activated is triggered only if double-clicked).
Maybe, you could just block all signals while making your change?
QSignalBlocker or QObject::blockSignals could help:
{
const QSignalBlocker blocker(myWidget);
myWidget->setCurrentIndex(someIndex);
}
In your slot, you can use QObject::sender() to return the QObject to you. From there, there are a handful of ways you should be able to distinguish the source.
What I finally did, and it works in my case because I have a single-thread application, I created a custom variable programmatic-select, which I set to true before calling setCurrentIndex(). In the changeSelection()-slot I check this variable and do nothing if it is true.
Very important for this to work is to connect the slot to the signal with the connection-type DirectConnection. In this case the slot is executed synchronously when the signal is emitted and I'm sure the value of my variable is safe.
I have the following code that performs a background operation (scan_value) while updating a progress bar in the ui (progress). scan_value iterates over some value in obj, emitting a signal (value_changed) each time that the value is changed. For reasons which are not relevant here, I have to wrap this in an object (Scanner) in another thread. The Scanner is called when the a button scan is clicked. And here comes my question ... the following code works fine (i.e. the progress bar gets updated on time).
# I am copying only the relevant code here.
def update_progress_bar(new, old):
fraction = (new - start) / (stop - start)
progress.setValue(fraction * 100)
obj.value_changed.connect(update_progress_bar)
class Scanner(QObject):
def scan(self):
scan_value(start, stop, step)
progress.setValue(100)
thread = QThread()
scanner = Scanner()
scanner.moveToThread(thread)
thread.start()
scan.clicked.connect(scanner.scan)
But if I change the last part to this:
thread = QThread()
scanner = Scanner()
scan.clicked.connect(scanner.scan) # This was at the end!
scanner.moveToThread(thread)
thread.start()
The progress bar gets updated only at the end (my guess is that everything is running on the same thread). Should it be irrelevant if I connect the signal to a slot before of after moving the object receiving object to the Thread.
It shouldn't matter whether the connection is made before or after moving the worker object to the other thread. To quote from the Qt docs:
Qt::AutoConnection - If the signal is emitted from a different
thread than the receiving object, the signal is queued, behaving as
Qt::QueuedConnection. Otherwise, the slot is invoked directly,
behaving as Qt::DirectConnection. The type of connection is
determined when the signal is emitted. [emphasis added]
So, as long as the type argument of connect is set to QtCore.Qt.AutoConnection (which is the default), Qt should ensure that signals are emitted in the appropriate way.
The problem with the example code is more likely to be with the slot than the signal. The python method that the signal is connected to probably needs to be marked as a Qt slot, using the pyqtSlot decorator:
from QtCore import pyqtSlot
class Scanner(QObject):
#pyqtSlot()
def scan(self):
scan_value(start, stop, step)
progress.setValue(100)
EDIT:
It should be clarified that it's only in fairly recent versions of Qt that the type of connection is determined when the signal is emitted. This behaviour was introduced (along with several other changes in Qt's multithreading support) with version 4.4.
Also, it might be worth expanding further on the PyQt-specific issue. In PyQt, a signal can be connected to a Qt slot, another signal, or any python callable (including lambda functions). For the latter case, a proxy object is created internally that wraps the python callable and provides the slot that is required by the Qt signal/slot mechanism.
It is this proxy object that is the cause of the problem. Once the proxy is created, PyQt will simply do this:
if (rx_qobj)
proxy->moveToThread(rx_qobj->thread());
which is fine if the connection is made after the receiving object (i.e. rx_qobj) has been moved to its thread; but if it's made before, the proxy will stay in the main thread.
Using the #pyqtSlot decorator avoids this issue altogether, because it creates a Qt slot more directly and does not use a proxy object at all.
Finally, it should also be noted that this issue does not currently affect PySide.
My problem was solved by movinf the connection to the spot where the worker thread is initialized, in my case because I am accessing an object which only exists after instantiation of my Worker Object class which is in another thread.
Simply connect the signal after the self.createWorkerThread()
Regards
This has to do with the connection types of Qt.
http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html#connect
http://qt-project.org/doc/qt-4.8/qt.html#ConnectionType-enum
In case both objects live in the same thread, a standard connection type is made, which results in a plain function call. In this case, the time consuming operation takes place in the GUI thread, and the interface blocks.
In case the connection type is a message passing style connection, the signal is emitted using a message which is handled in the other thread. The GUI thread is now free to update the user interface.
When you do not specify the connection type in the connect function, the type is automatically detected.
I have an application with many windows (QWidgets).
I didn't save a list of open windows, though, so everytime I want to close a window, I have to retrieve it.
Particularly, each of these windows is called here SubWindow.
Every SubWindow class contains a layout with a MultiEditor *sEditors, which has a menu with an action that closes the current window.
Every SubWindow is created within the MainWindow.
I have two plans.
1) destroying the SubWindow from within itself, by adding in the SubWindow constructor
connect(sEditors, SIGNAL(closeWindow()),
this, closeWindow()));
or
2) destroying the SubWindow from within the MainWindow class, by adding in the SubWindow constructor
connect(sEditors, SIGNAL(closeWindow()),
main, SLOT(closeWindow(this)));
About 1), I don't understand how I can close and destroy a QWidget from within itself (delete this; didn't seem to work, but I can try again).
About 2) my SLOT(closeWindow(this)) doesn't seem to be triggered, so I am wondering if I can pass "this" as an argument.
Ad 1) You can use QObject::deleteLater(). This will destroy the object in the next event loop cycle, and is specifically create for situations like this
Ad 2) You cannot pass actual arguments as parameters in signal-slot connections.
You can however find out who has emitted the signal by using the sender() function in the slot. In your case, that would be the sEditors object.
Other options:
3) You can use a QSignalMapper to map signals from your editors to the Subwindows.
4) (Using Qt5 / C++11) You can use a lambda connection in your Subwindows:
connect(sEditors, SIGNAL(closeWindow()), [this] () {this->closeWindow();});
Can I pass this to a Qt slot?
A slot is a non-static method, so it already has access to this. The this you refer to is the third argument to QObject::connect. In Qt 4 syntax, you're free to omit the third argument - it defaults to this. In Qt 5 syntax, you must be explicit about it, though.
I don't understand how I can close and destroy a QWidget from within itself
To delete any QObject from within itself, use QObject::deleteLater(). Recall that a QWidget is-a QObject in terms of LSP.
my SLOT(closeWindow(this)) doesn't seem to be triggered
There's no such slot (give us a link to its documentation: you can't), and your slot signature is also invalid because the only things within the parentheses in the slot signature can be types, and this is not a type: SLOT(slotName(TYPE_LIST_HERE)), e.g. SLOT(mySlot(int,QString)).
To close a widget, use its close() slot:
connect(sEditors, SIGNAL(closeWindow()), this, SLOT(close());
Yet, by using Qt 4 connect syntax, you're leaving coding mistakes to be detected at runtime - and then if you don't pay attention to the debug output at runtime, you'll miss it. It's thus much better to use the new (Qt 5) connect syntax, and let the compiler detect errors for you:
connect(sEditors, &MultiEditor::closeWindow, this, &QWidget::close);
Alas, there's no need to tightly couple the object that sends closeWindow to SubWindow - at least not within the SubWindow::SubWindow(). Instead, you can connect at the place where you create the editor.
To delete a widget when it gets closed, simply set the Qt::WA_DeleteOnClose attribute on it and let Qt do it for you. No need to explicitly call deleteLater etc.
You might factor all of it into a factory method:
template <class T> T* SubWindow::makeEditor() {
auto sub = new T{this};
sub->setAttribute(Qt::WA_DeleteOnClose);
connect(sEditor, &MultiEditor::closeWindow, sub, &QWidget::close);
return sub;
}
MainWindow::MainWindow(/*...*/) : /*...*/ {
makeEditor<EditorType1>();
makeEditor<EditorType2>();
/*...*/
}
In main, I'm creating a QApplication in a thread I create, and then, according to commands from the user (from cin), I want to use callbacks on the QApplication instance I created in the thread.
The creation of the QApllication happens on a workerthread that is called 'StartQtThread', and my main function, in which I get the commands is the main thread.
my problem is that my commands from the main thread, don't work on the qapplication.
for example: if the user enters 'z', I cant to zoom in , on the map in my QApplication. bus since I'm on the main thread nothing happens.
I tried to use my zoom-in function, from the 'StartQtThread' thread, it works.
tried to use 'moveToThread(qApp->thread())' function from the main thread , but the current thread isn't being changed.
anyone knows how can I change that?
thread->moveToThread(obj) moves object obj to the thread thread. Code moveToThread(qApp->thread()) moves main thread's object to another thread (which is kinda strange). GUI can work ONLY in main thread.
I'm facing a practical problem with Qt. I'm using a class that communicates with QLocalSocket to another process (pipes/unix sockets) and I need to do that communication before other events occur, that is before app.exec() starts (or more precisely,as soon as app starts). The class that I'm using needs an eventloop so it does not work if I call the class methods before an event loop is started. There is any way to start something when the event loop is ready? I thought of making a hidden event-only window and do my duties in the hidden window constructor, and stablish this window as toplevel.
Basically, I need this local-socket communication task to start as soon as the event loop becomes available.
Any ideas?
Thank you.
You could start a separate eventloop, using QEventLoop, before calling QApplication::exec(). You should emit a "done" signal from your class and connect that to the QEventLoop quit() slot, or use an existing signal provided in the Qt class you're using.
Here's a simple example fetching a webpage using QNetworkAccessManager:
app = QtCore.QCoreApplication([])
manager = QtNetwork.QNetworkAccessManager()
req = QtNetwork.QNetworkRequest(QtCore.QUrl("http://www.google.com"))
resp = manager.get(req)
eventloop = QtCore.QEventLoop()
eventloop.connect(resp, QtCore.SIGNAL('finished()'), QtCore.SLOT('quit()'))
eventloop.exec_() # this will block until resp emits finished()
print resp.readAll()
app.exec_()
While this might suit your needs, I couldn't quite understand why you can't simply do whatever business you have prior to calling show() on your window, once that's done, call show().
If you just need to start the communications before everything else, you can simply use a single-shot timer with 0ms delay:
QTimer::singleShot(0, commsInstancePtr, SLOT(startCommunication()));
If you need your operations to actually finish before doing everything else, Daniel's solution might be more suitable.