QtCore.QObject.connect(my_button, QtCore.SIGNAL('clicked()'), my_func)
and
my_button.clicked.connect(my_func)
I usually use the first option, but then I found the second one and want to know what is a difference between them.
The first option is the old-style signal and slot syntax, which is now obsolete. You can still use it in PyQt4, but it is not supported at all in PyQt5. The second option is the new-style signal and slot syntax, which can be used in PyQt5 and all recent versions of PyQt4 (it was introduced in v4.5).
The PyQt docs lists the following disadvantages of the old-style syntax:
It requires knowledge of the C++ types of signal arguments.
It is error prone in that if you mis-type the signal name or signature - then no exception is raised, either when the signal is
connected or emitted.
It is verbose.
It is not Pythonic.
Related
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'm learning PyQt (I haven't used C++ Qt before).
I don't understand the reason for signals and slots. That is, it seems I can do everything by calling the methods of classes directly. Doing so seems more Pythonic, uses less code and is easier to read. What am I missing?
For clarification, I'm asking why I would do this:
def mouseReleaseEvent(self):
self.clicksignal.connect(ui.iconClicked)
self.clicksignal.emit()
when I can do this:
def mouseReleaseEvent(self):
ui.iconClicked()
The reason signals and slots exist is because you cannot change the GUI from any other thread of the application except the UI thread.
If you have some heavy CPU intensive calculation to do, or any task that waits for IO or something like that... if you do it the UI thread (for example if you fetch a url or something that lasts some time), your UI thread will be busy, and the GUI event loop wont be able to update itself, so the GUI will seem frozen.
To do these kind of operations. you execute them in a separate (background worker) thread, so the UI thread can continue updating the GUI.
Now the problem is that you cannot access the elements of the GUI and change their state from any other thread except the UI thread. So signals and slots are introduced. When you emit a signal it is guaranteed to be caught in the UI thread, and the slot will be executed in the UI thread.
I'm not exactly sure what you try to accomplish in your example, but this is the main reason why signals and slots exist. Basically UI thread should only deal with the UI, and everything else should be done in the background worker thread that sends a signal that gets caught in the UI thread and the slot that update the GUI is executed in the UI thread.
Well... yes, you can. But you need to think bigger. In your example code, caller of mouseReleaseEvent must have the reference to the object that receives the notification, and explicitly invoke appropriate method. Using slot & signals mechanism decouples event producer (e.g. widget) from event consumer - pretty much arbitrary other object. This makes setting up communication and control flow easier and external to the low-level UI components, which is the good thing. It also makes such components reusable - by moving wiring code outside, we make it independent of the application logic.
In addition to the answers by #ViktorKerkez and #Wilbur, signals and slots provide a notification system of fire and forget, as well as decoupling classes.
A great advantage of this is that a class can emit a signal, not knowing what or who is going to receive the message. It may be just one object that has a slot connected, or it could be dozens. Alternatively, you may want a single class with one slot that is connected to multiple signals. So it can be used as a notification system.
For example, imagine a program where many different types of objects send information to a log. The objects simply emit a Log(text) signal and do not care about what actually does the logging. These signals can be connected to a log class which can be either logging to a file, over a network, to the screen, or all at once. The objects logging don't care.
I have trouble doing cleanup just before the application quits - my cleanup is called before other essential events are happen.
Currently I am using
QObject.connect(self.qtApp,
SIGNAL("lastWindowClosed()"),
self._lastWindowClosed)
My application consists of a single QtGui.QDialog, that throws SIGNAL("accepted()") or SIGNAL("rejected()") (OK or Cancel buttons). If I do my cleanup as shown above, I miss those events. If I do my cleanup on SIGNAL("aboutToQuit()"), I do not miss those events.
I fail to discover meaningful documentation on any of the two signals. For example PySide's documentation on aboutToQuit and lastWindowClosed talks about some filepths and nothing related to the lifetime of the application.
It appears that I need to use aboutToQuit(). Where can I find meaningful documentation on this signal, so that I am sure no events are missed before it?
See the QCoreApplication::aboutToQuit documentation page:
The signal is particularly useful if your application has to do some last-second cleanup. Note that no user interaction is possible in this state.
So if you want to do cleanup, this signal should be used.
The lastWindowClosed signal is emitted when all windows are closed. It doesn't necessarily lead to the application termination. And emitting this signal on application termination is not guaranteed (for example, it will not be emitted when closing application programmatically using QApplication::quit).
I've seen some example code for PySide slots that uses the #QtCore.Slot decorator, and some that does not. Testing it myself, it doesn't seem to make a difference. Is there a reason I should or should not use it? For example, in the following code:
import sys
from PySide import QtCore
# the next line seems to make no difference
#QtCore.Slot()
def a_slot(s):
print s
class SomeClass(QtCore.QObject):
happened = QtCore.Signal(str)
def __init__(self):
QtCore.QObject.__init__(self)
def do_signal(self):
self.happened.emit("Hi.")
sc = SomeClass()
sc.happened.connect(a_slot)
sc.do_signal()
the #QtCore.Slot decorator makes no difference; I can omit it, call #QtCore.Slot(str), or even #QtCore.Slot(int), and it still nicely says, "Hi."
The same seems to be true for PyQt's pyqtSlot.
This link explains the following about the pyqtSlot decorator:
Although PyQt4 allows any Python callable to be used as a slot when
connecting signals, it is sometimes necessary to explicitly mark a
Python method as being a Qt slot and to provide a C++ signature for
it. PyQt4 provides the pyqtSlot() function decorator to do this.
and
Connecting a signal to a decorated Python method also has the
advantage of reducing the amount of memory used and is slightly
faster.
Since the pyqtSlot decorator can take additional argument such as name, it allows different Python methods to handle the different signatures of a signal.
If you don't use the slot decorator, the signal connection mechanism has to manually work out all the type conversions to map from the underlying C++ function signatures to the Python functions. When the slot decorators are used, the type mapping can be explicit.
Austin has a good answer, and the answer I'm about to write is a bit outside the scope of your question, but it's something that has been confusing me and I imagine others will end up on this page wondering the same thing.
If you want to expose Python methods to JavaScript (using QTWebKit), then the #pyqtSlot decorator is mandatory. Undecorated methods are not exposed to JavaScript.
In a multithreaded environment, it may be mandatory not to use the pyside Slot decorator, because it can cause signals to go to the wrong thread. See
Derived classes receiving signals in wrong thread in PySide (Qt/PyQt)
https://bugreports.qt.io/browse/PYSIDE-249
I'm wanting a paradigm in a Qt4 (PyQt4) program where a component is able to respond to a signal without knowing anything about where it is coming from.
My intial reading suggests that I have to explicitly connect signals to slots. But what I want is for any of a number of components to be able to send a signal, and for it to be processed by another component.
Comparing with another toolkits, for example, in wxWidgets I would use events. These automatically propogate up from child windows/objects to parents. At each level they can be handled. This means if I have a lot of children which may emit the same event, I don't have to explicitly connect all of them to the handler. I can just put the handler in the parent, or some higher level in the window hierarchy. This means that only the event generator and consumer need to know about the event at all. The consumer doesn't need to know where the source of the event is, how many such sources there are, or anything else about it.
Is this possible in Qt - is there another approach? Maybe there is an alternative event mechanism to signals and slots?
This isn't easily possible - you have to have something that knows about the signaling object and the receiving object to connect the two. Depending on what you need, however, you might be able to set up a class that mediates between the two (so objects with signals tell the class they exist, and have such-and-such a signal, while objects with slots tell the class they exist and have such-and-such a slot to connect to a given signal, and the mediator class tracks both of those, making connections when necessary).
Don't you just want a good old fashioned method invocation? The response is just the return value of the method.
Signal handlers do NOT know the emitter (only the signal type) and emitters do NOT know what handlers are connected. Many handlers can connect to the same signal and they are executed in the order of connection. A signal can be emitted from many places.