I have something like the following design of classes and I'm wondering if it's OK that I use many signal slot connections to communicate between them. There is a MainWindow class which holds all the GUI, then a Wrapper class, which provides an interface to the back-end, then there is a Controller class for spawning and managing threads and finally there are Workers which do all the work.
Now let's say I'm loading a file and want to display progress using a progress bar in the MainWindow. My Worker class sends updateProgress(int progress) to Controller::handleProgress(int progress) slot which again sends progress signal to the Wrapper class, which in return sends a progress signal to the main window, which finally updates the progress bar.
Similarly when the data has been loaded it is processed in the Wrapper class and, again, communicated through signals and slots (although with one less step).
Is it a standard way of doing things in Qt or should I rethink my design?
It is a valid possibility.
Note that Qt allows you to go even further and do the following:
QObject::connect(&sender, SIGNAL(mySenderSignal(int)),
&receiver, SIGNAL(myReceiverSignal(int));
That's right, you can bind a signal to a signal. All it does can be seen as "when the sender's signal is emitted, emit the receiver's signal".
If you don't have any specific task to perform in your intermediary slots, that might save you a few lines, while showing exactly what you're doing: you're "forwarding" a signal. Otherwise, if you must absolutely do work in between, then you must keep the signals and the slots.
Note that you still have to be sure that the signals signatures match.
Related
My first naive at updating my progress bar was to include the following lines in my loop which is doing the processing, making something like this:
while(data.hasMoreItems())
{
doSomeProcessing(data.nextItem())
//Added these lines but they don't do anything
ui->progressBar->setValue(numberProcessed++);
ui->progressBar->repaint();
}
I thought adding the repaint() would make the execution pause while it updated the GUI, but apparently it's not that simple. After looking at the questions:
QProgressBar Error
Progress bar is not showing progress
it looks like I'm going to have to put the data processing in a different thread and then connect a signal from the data processing thread to the GUI thread to update the progressbar. I'm rather inexperienced with GUIs and threads and I was wondering if anyone could just point me in the right direction, ie what Qt classes should I be looking at using for this. I'd guess I need a QThread object but I've been looking through the QProgressBar documentation but it doesn't bring up the topic of threading.
As #rjh and #Georg have pointed out, there are essentially two different options:
Force processing of events using QApplication::processEvents(), OR
Create a thread that emits signals that can be used to update the progress bar
If you're doing any non-trivial processing, I'd recommend moving the processing to a thread.
The most important thing to know about threads is that except for the main GUI thread (which you don't start nor create), you can never update the GUI directly from within a thread.
The last parameter of QObject::connect() is a Qt::ConnectionType enum that by default takes into consideration whether threads are involved.
Thus, you should be able to create a simple subclass of QThread that does the processing:
class DataProcessingThread : public QThread
{
public:
void run();
signals:
void percentageComplete(int);
};
void MyThread::run()
{
while(data.hasMoreItems())
{
doSomeProcessing(data.nextItem())
emit percentageCompleted(computePercentageCompleted());
}
}
And then somewhere in your GUI code:
DataProcessingThread dataProcessor(/*data*/);
connect(dataProcessor, SIGNAL(percentageCompleted(int)), progressBar, SLOT(setValue(int));
dataProcessor.start();
You need to call QApplication::processEvents() periodically inside your processing loop to let it handle UI events.
As Georg says, Qt is a single-threaded co-operative multitasking environment. You get full control of your process until you relinquish it voluntarily with processEvents() - until you do that, Qt can't update the UI elements, handle async HTTP requests, handle input, or pretty much anything else. It's up to you to make sure that stuff gets a timeslice while you're in a long processing loop.
You can create a sub-class of QThread that emits a signal progressChanged, which you connect to the QProgressBar.
connect() makes the connections auto connections per default. That means that the signal-slot-mechanism already takes care of the threading issues for you, so you don't need to worry about that.
Does Qt offer functionality to know the number of queued signals that are pending for a given slot to process? Is there a way to clear them? For example, if several emits are done on a signal connected to a given slot, how could someone know the amount of these emitted signals?
QMetaObject::Connection class has a laconic interface and does not seem to offer related functionality. Deleting the object that receives the signals, hence destroying the connections, solves the problem. But is there a way to do this without disconnecting the slots or deleting the receiving objects?
The reason you ask the question most likely indicates that your design is broken. The signals and slots are a mechanism to decouple code. The objects connected together should behave themselves no matter how many senders or receiver are there, and certainly shouldn't attempt to track such matters!
It'd be wiser to fix the issue at the source by altering the design. If you are uffering from an event storm e.g. due to changing a widget's data in a slot, the slot should be very lightweight and only schedule an update of the widget by calling update(), but never forcing an immediate repaint. This leverages repaint event compression done by Qt. You might wish to compress your own events too.
Connection types in Qt
Signals and slots in Qt can be delivered using a direct, queued or blocking connection. The automatic type is not really a fixed connection type. It is an instruction to resolve the type for every receiver, at every signal emission into either a direct or queued type.
The direct connection is like any indirect function call: nothing is queued, and the slot is called from within the body of the signal method:
// all direct-connected slots/functors are invoked before mySignal() returns
emit mySignal();
The queued connection posts a QMetaCallEvent to the receiving object thread's event loop. That event contains the arguments of the call, or carries the functor. Is is handled by QObject::event(). You can certainly intercept such events. For details, see this question.
As far as I know, it is not possible to access the queue.
First of all, if the slot is in a QWidget subclass, in the GUI thread, then you can just update the member variables and call update(), and then just use the current values in paintEvent() when it gets called. These are automatically compressed, so there will be just one repaint event, no matter how many times update() gets called.
However, if the slot is not related to painting, or not in the GUI thread at all, then you need something else.
A simple solution to many cases needing this is to use a 2nd slot and a single-shot QTimer with delay 0 (or even longer delay if desirable).
Here's some example code, which should give you the idea of what I mean:
// in constructor, set mActualSlotTimer to
// singleshot, interval 0, parent this (needed for multi-threaded use)
// and connect timeout() to privateActualSlot()
// public slot for receiving the signal from outside
void MyClass::actualSlot(int data) {
// class member to store the new data value until it can be set
mNewData = data;
// restart the timer, no matter if it was already running or not
mActualSlotTimer.start();
}
// "private" slot for actually doing the change
void MyClass::privateActualSlot() {
// maybe useful: if (this->mData == this->mNewData) return;
mData = mNewData;
// do whatever else needs to be done!
}
Obviously, if your public slot does not actually take any parameters, then you don't need mData and mNewData.
One thing to note about this approach is, it works on all connections, it's not limited to just Qt::QueuedConnecton. As a consequence, it also makes using Qt::BlockingQueuedConnection kinda pointless.
A disclaimery note: I briefly checked Qt source code and it seems using timer with interval 0 should be ok: restarting the timer will work as expected. But if there still seems to be too many calls to privateActualSlot, then providing a suitable interval might be necessary. I have usually wanted a little delay (5 ms for example) to throttle things down a bit more than "as often as possible", so have not tested this extensively with interval 0.
Under Qt 4.7.1, Qt Creator 2.1.0, OS X 10.6.8:
I have a QLabel in the mainwindow ui, which uses Courier New / 13, with room for four lines of text.
I create four lines of text, considerably shorter than the label is horizontally, of the general format:
"my text\r\n"
I filter the text before sending it along. The only characters in the cstring will be 0x0D, 0x0A, 0x20 (space) and from there up to lower case z (0x7A') and of course the terminating zero. No other control characters - if they are received from the source, I replace them with '*'
I send the four lines of text to the QLabel as a single zero-terminated cstring via setText()
I sometimes do this at a fairly high rate, several times a second at least -- this is RDBS data from an FM station so it changes in real time:
qDebug() << rbl; // data keeps coming to console
ui->fourLineLabel->setText(rbl); // add this, display soon stops updating
This works. For a while. Then the display stops updating. This is the area at issue:
(source: fyngyrz.com)
If I leave everything else in, but take out the setText(), the problem does not occur.
I know that for some things, Qt wants painting to be done within a paint event. Is this also true of a setText() ?
Reading the docs on qt widgets, it says that widgets do their own painting within their own paint event... but the behavior here is very similar to the kind of malfappery that goes on when one actually tries to use a painter outside of a paint event. And it's definitely related to that setText(), so... mumble.
As I write this, the application has been running for hours without any display lockup, outputting the same text to the console via qDebug(). It takes about 5 minutes for the problem to occur if I uncomment the setText(). It's 100% repeatable.
Is there something I should be doing that I'm not doing, paint-wise or similar?
Thanks for any assistance.
In general you should not update Qt controls from non UI thread, only a small amount of things is allowed to do regarding a painting in non UI thread - http://doc.qt.io/qt-4.8/threads-modules.html
If you need to update UI from non UI thread - use signals and slots (QueuedConnection or BlockingQueuedConnection connections, though make sure to not create deadlock with BlockingQueuedConnection). Or if you don't want to create additional signals and slots for some easy update - use invokeMethod (it can even return value and if you use it with BlockingQueuedConnection connection type, your thread will wait until UI is updated).
And a general advice - if you have a possibility - make one call for bulk of updates to UI instead of few small calls.
It is always advised that the GUI thread interfaces with all other objects through the signal-slot mechanism. In fact, no direct calls from and to the main thread are to be made. In that manner the GUI will be responsive, and we don't end up waiting for it to come back. Certainly polling solutions are not ideal, and should be avoided as they end up using cup resources without reason.
If one is using only QThread type threads then updating the GUI should be done by using the signal-slot mechanism. When events of data presented need to be serialized using the Qt::QueuedConnection is sufficient. In your case that is true.
If not using that , then signals may not be processed in the sequence emitted. Qt::BlockingQueuedConnection should be used only when we want to restrict the caller continue from processing before the slot on the receiver has completed. This is very rarely the case for processing that happens on the GUI thread.
Special care has to be taken when we want to connect from a non-qt thread, e.g. An std thread, because the objects created e.g. in a native thread will not be known on the receiver end.
One way to update the ui from a non-ui thread is to serialize and copy your messages. Do the following (works even for non-QThreads e.g. boost::thread ):
Setup a singleton QObject that provides public methods to force-emit
signals containing the data that you want to send ,e.g. a singleton
Setup slots in objects that only accept arguments by value
Connect the signals to the slots in an object within the ui-thread
Connections must be Qt::QueuedConnection
class timer : public QObject
{
Q_OBJECT
//... write a singleton here
std::mutex mut;
public signals:
signal_tic(QString const );
public:
void force_emit_tic(QString const s )
{
std::lock_guard<std::mutex> l(mut);
emit signal_tic(s);
}
timer & ref()
{
static timer This;
return This;
}
private:
timer(){}
};
// in a main thread object setup this connection
connect(&timer::ref(),SIGNAL(signal_tic(Qstring
const)),this,SLOT(slot_accept_tic(QString const ), Qt::QueuedConnection)
// In any other thread
timer::ref()::force_emit_tic( string_when_this_happened )
Calling directly the singleton force-emit method results in the desired behaviour. (ofcourse objects must be properly copiable for this to work)
The reason for sending by value is that if you pass a const reference to temporary residing in another thread it's lifetime is not guaranteed. Furthermore, you need to take care of serializing the messages to the ui-thread before they actually arrive or you will eventually receive one of either incosistent data or a SIGSEGV. Qt::QueuedConnection guarantees that connections are serialized only within the memory space known to QThreads.
I have some problems with Qt. I have a class with a signal who's parameters are strings, and a slot. I'm connecting the signal to the slot in the class constructor. Also, I'm creating a thread in the class constructor. The thread reads data from a server and updates the UI(emits the UpdateMe signal). This is how I connect the signal to the slot:
QObject::connect(this, SIGNAL(UpdateMe(string, string)), this, SLOT(ModifyUI(string, string)));
I have a QTreeWidget with some file names. When I rename a file I notify the server and the server notifies the other clients. When I connect a single client there is no problem, but when I connect more than one client a problem appears: when I notify the server from the second client(when I write into the socket) the following error appears:
QObject::connect: Cannot queue arguments of type 'QVector<int>'
I tried to register QVector with qRegisterMetaType but I also have a signal that is emited when I modify an QTreeWidgetItem(when I rename the item, for example) and I need to dissconnect this signal when I want to change the item's text. If I register QVector I can't dissconnect this signal and the signal is emited.
When you register the QVector, does your call look like this?
qRegisterMetaType<QVector<int> >("QVector<int>");
Once you make this call, you should be able to emit the QVector type over queued connections.
If I register QVector I can't dissconnect this signal and the signal is emited.
Registering a metatype shouldn't prevent you from disconnecting a signal. It just allows you to queue types that aren't already registered with the meta system.
Most of the time, errors which look like this seem to be a result of mixing up threads, and specifically with this one, in my (limited) experience, a result of attempting to manipulate GUI elements "held" in the GUI thread using commands run a worker QThread.
I say "held" because quite often you get a complaint/error/crash saying something like "QObject: Cannot create children for a parent that is in a different thread." (i.e. the GUI thread).
The solution: from a non-GUI QThread ALWAYS communicate with GUI elements using signals and slots.
In the Qt world, what is the difference of events and signal/slots?
Does one replace the other? Are events an abstraction of signal/slots?
In Qt, signals and events are both implementations of the Observer pattern. They are used in different situations because they have different strengths and weaknesses.
First of all let's define what we mean by 'Qt event' exactly: a virtual function in a Qt class, which you're expected to reimplement in a base class of yours if you want to handle the event. It's related to the Template Method pattern.
Note how I used the word "handle". Indeed, here's a basic difference between the intent of signals and events:
You "handle" events
You "get notified of" signal emissions
The difference is that when you "handle" the event, you take on the responsibility to "respond" with a behavior that is useful outside the class. For example, consider an app that has a button with a number on it. The app needs to let the user focus the button and change the number by pressing the "up" and "down" keyboard keys. Otherwise the button should function like a normal QPushButton (it can be clicked, etc). In Qt this is done by creating your own little reusable "component" (subclass of QPushButton), which reimplements QWidget::keyPressEvent. Pseudocode:
class NumericButton extends QPushButton
private void addToNumber(int value):
// ...
reimplement base.keyPressEvent(QKeyEvent event):
if(event.key == up)
this.addToNumber(1)
else if(event.key == down)
this.addToNumber(-1)
else
base.keyPressEvent(event)
See? This code presents a new abstraction: a widget that acts like a button, but with some extra functionality. We added this functionality very conveniently:
Since we reimplemented a virtual, our implementation automatically became encapsulated in our class. If Qt's designers had made keyPressEvent a signal, we would need to decide whether to inherit QPushButton or just externally connect to the signal. But that would be stupid, since in Qt you're always expected to inherit when writing a widget with a custom behavior (for good reason - reusability/modularity). So by making keyPressEvent an event, they convey their intent that keyPressEvent is just a basic building block of functionality. If it were a signal, it'd look like a user-facing thing, when it's not intended to be.
Since the base-class-implementation of the function is available, we easily implement the Chain-of-responsibility pattern by handling our special cases (up&down keys) and leaving the rest to the base class. You can see this would be nearly impossible if keyPressEvent were a signal.
The design of Qt is well thought out - they made us fall into the pit of success by making it easy to do the right thing and hard to do the wrong thing (by making keyPressEvent an event).
On the other hand, consider the simplest usage of QPushButton - just instantiating it and getting notified when it's clicked:
button = new QPushButton(this)
connect(button, SIGNAL(clicked()), SLOT(sayHello())
This is clearly meant to be done by the user of the class:
if we had to subclass QPushButton every time we want some button to notify us of a click, that would require a lot of subclasses for no good reason! A widget that always shows a "Hello world" messagebox when clicked is useful only in a single case - so it's totally not reusable. Again, we have no choice but to do the right thing - by connecting to it externally.
we may want to connect several slots to clicked() - or connect several signals to sayHello(). With signals there is no fuss. With subclassing you would have to sit down and ponder some class diagrams until you decide on an appropriate design.
Note that one of the places QPushButton emits clicked() is in its mousePressEvent() implementation. That doesn't mean clicked() and mousePressEvent() are interchangable - just that they're related.
So signals and events have different purposes (but are related in that both let you "subscribe" to a notification of something happening).
I don’t like the answers so far. – Let me concentrate on this part of the question:
Are events an abstraction of signal/slots?
Short answer: no. The long answer raises a “better” question: How are signals and events related?
An idle main loop (Qt’s for example) is usually “stuck” in a select() call of the operating system. That call makes the application “sleep”, while it passes a bunch of sockets or files or whatever to the kernel asking for: if something changes on these, let the select() call return. – And the kernel, as the master of the world, knows when that happens.
The result of that select() call could be: new data on the socket connect to X11, a packet to a UDP port we listen on came in, etc. – That stuff is neither a Qt signal, nor a Qt event, and the Qt main loop decides itself if it turns the fresh data into the one, the other or ignores it.
Qt could call a method (or several) like keyPressEvent(), effectively turning it into a Qt event. Or Qt emits a signal, which in effect looks up all functions registered for that signal, and calls them one after the other.
One difference of those two concepts is visible here: a slot has no vote on whether other slots registered to that signal will get called or not. – Events are more like a chain, and the event handler decides if it interrupts that chain or not. Signals look like a star or tree in this respect.
An event can trigger or be entirely turned into a signal (just emit one, and don’t call “super()”). A signal can be turned into an event (call an event handler).
What abstracts what depends on the case: the clicked()-signal abstracts mouse events (a button goes down and up again without too much moving around). Keyboard events are abstractions from lower levels (things like 果 or é are several key strokes on my system).
Maybe the focusInEvent() is an example of the opposite: it could use (and thus abstract) the clicked() signal, but I don’t know if it actually does.
The Qt documentation probably explains it best:
In Qt, events are objects, derived
from the abstract QEvent class, that
represent things that have happened
either within an application or as a
result of outside activity that the
application needs to know about.
Events can be received and handled by
any instance of a QObject subclass,
but they are especially relevant to
widgets. This document describes how
events are delivered and handled in a
typical application.
So events and signal/slots are two parallel mechanisms accomplishing the same things. In general, an event will be generated by an outside entity (for example, keyboard or mouse wheel) and will be delivered through the event loop in QApplication. In general, unless you set up the code, you will not be generating events. You might filter them through QObject::installEventFilter() or handle events in subclassed object by overriding the appropriate functions.
Signals and Slots are much easier to generate and receive and you can connect any two QObject subclasses. They are handled through the Metaclass (have a look at your moc_classname.cpp file for more), but most of the interclass communication that you will produce will probably use signals and slots. Signals can get delivered immediately or deferred via a queue (if you are using threads).
A signal can be generated.
Events are dispatched by the event loop. Each GUI program needs an event loop, whatever you write it Windows or Linux, using Qt, Win32 or any other GUI library. As well each thread has its own event loop. In Qt "GUI Event Loop" (which is the main loop of all Qt applications) is hidden, but you start it calling:
QApplication a(argc, argv);
return a.exec();
Messages OS and other applications send to your program are dispatched as events.
Signals and slots are Qt mechanisms. In the process of compilations using moc (meta-object compiler), they are changed to callback functions.
Event should have one receiver, which should dispatch it. No one else should get that event.
All slots connected to the emitted signal will be executed.
You shouldn't think of Signals as events, because as you can read in the Qt documentation:
When a signal is emitted, the slots connected to it are usually executed immediately, just like a normal function call. When this happens, the signals and
slots mechanism is totally independent
of any GUI event loop.
When you send an event, it must wait for some time until the event loop dispatches all events that came earlier. Because of this, execution of the code after sending event or signal is different. Code following sending an event will be run immediately. With the signals and slots mechanisms it depends on the connection type. Normally it will be executed after all slots. Using Qt::QueuedConnection, it will be executed immediately, just like events. Check all connection types in the Qt documentation.
There is an article that discusses event processing in some detail: http://www.packtpub.com/article/events-and-signals
It discussions the difference between events and signals here:
Events and signals are two parallel mechanisms used to accomplish the
same thing. As a general difference, signals are useful when using a
widget, whereas events are useful when implementing the widget. For
example, when we are using a widget like QPushButton, we are more
interested in its clicked() signal than in the low-level mouse press
or key press events that caused the signal to be emitted. But if we
are implementing the QPushButton class, we are more interested in the
implementation of code for mouse and key events. Also, we usually
handle events but get notified by signal emissions.
This seems to be a common way of talking about it, as the accepted answer uses some of the same phrases.
Note, please see helpful comments below on this answer from Kuba Ober, that make me wonder if it might be a bit simplistic.
TL;DR: Signals and slots are indirect method calls. Events are data structures. So they are quite different animals.
The only time when they come together is when slot calls are made across thread boundaries. The slot call arguments are packed up in a data structure and get sent as an event to the receiving thread's event queue. In the receiving thread, the QObject::event method unpacks the arguments, executes the call, and possibly returns the result if it was a blocking connection.
If we're willing to generalize to oblivion, one could think of events as as a way of invoking the target object's event method. This is an indirect method call, after a fashion - but I don't think it's a helpful way of thinking about it, even if it's a true statement.
'Event processing' by Leow Wee Kheng says:
Jasmine Blanchette says:
The main reason why you would use events rather than standard function calls, or signals and slots, is that events can be used both synchronously and asynchronously (depending on whether you call sendEvent() or postEvents()), whereas calling a function or invoking a slot is always synchronous. Another advantage of events is that they can be filtered.
Events (in a general sense of user/network interaction) are typically handled in Qt with signals/slots, but signals/slots can do plenty of other things.
QEvent and its subclasses are basically just little standardized data packages for the framework to communicate with your code. If you want to pay attention to the mouse in some way, you only have to look at the QMouseEvent API, and the library designers don't have to reinvent the wheel every time you need to figure out what the mouse did in some corner of the Qt API.
It is true that if you're waiting for events (again in the general case) of some sort, your slot will almost certainly accept a QEvent subclass as an argument.
With that said, signals and slots can certainly be used without QEvents, although you'll find that the original impetus for activating a signal will often be some kind of user interaction or other asynchronous activity. Sometimes, however, your code will just reach a point where firing off a certain signal will be the right thing to do. For example, firing off a signal connected to a progress bar during a long process doesn't involve a QEvent up to that point.
Another minor pragmatic consideration: emitting or receiving signals requires inheriting QObject whereas an object of any inheritance can post or send an event (since you invoke QCoreApplication.sendEvent() or postEvent()) This is usually not an issue but: to use signals PyQt strangely requires QObject to be the first super class, and you might not want to rearrange your inheritance order just to be able to send signals.)
In my opinion events are completely redundant and could be thrown out. There is no reason why signals could not be replaced by events or events by signals, except that Qt is already set up as it is. Queued signals are wrapped by events and events could conceivably be wrapped by signals, for example:
connect(this, &MyItem::mouseMove, [this](QMouseEvent*){});
Would replace the convenience mouseMoveEvent() function found in QWidget (but not in QQuickItem anymore) and would handle mouseMove signals that a scene manager would emit for the item. The fact that the signal is emitted on behalf of the item by some outside entity is unimportant and happens quite often in the world of Qt components, even though it is supposedly not allowed (Qt components often circumvent this rule). But Qt is a conglomerate of many different design decisions and pretty much cast in stone for fear of breaking old code (which happens often enough anyway).