I've problem with qt signal-slot system.
First I've created a class which is called System in Singleton pattern, so I can access it's instance where I want. System has a signal SelectionChanged.
I've a list widget and I am connecting it's itemSelectionChanged signal to my custom slot which is called onSelectionChanged. In onSelectionChanged slot, I am emitting System's SelectionChanged signal. There is no problem yet.
In my software design, a selection of object(s) can be used by many GUI widgets or custom classes and System's SelectionChanged signal can be emited by widgets other then the list widget.
So I am creating a slot called OnSystemSelectionChanged in the list widget then connect it to the System's SelectionChanged signal. The OnSystemSelectionChangedSlot is like this.
void MyListWidget::OnSystemSelectionChanged(QObject *sender)
{
if (sender == this) return;
// Then I want to get a list of selected objects and set them as selection of this widget like this:
this->SetSelection(System::Instance()->GetSelectedObjects());
}
But the problem is when I start to set the list widget's selected items, it is going to emit itemSelectionChanged signal and my onSelectionChanged slot will be called. Then the slot will emit System's SelectionChanged signal and then OnSystemSelectionChanged will be called too. It will stop through sender parameter but there is no method for setting list widget's selected items at once.
How can I figure this problem out.
I hope I did explain my problem well. Thanks in advance.
Edit: Spelling and grammer errors are corrected.
There are a few ways of dealing with this in Qt.
Idioms
Use multiple views with one underlying model. This handles propagation of changes to multiple view controls automatically and you don't need to do anything extra. You can use QDataWidgetMapper to link "plain old" widgets to the data elements in a model. I'd say that this should be the preferred way of doing things. Having an underlying model for all of your UI is a step in the direction of good software design anyway.
When propagating changes between data models, implement both a DisplayRole and an EditRole. The views will nominally modify the models using one of the roles (say, the EditRole), while you can, programmatically, modify the models using the other role (say, the DisplayRole). You handle the dataChanged signals from the model in your own slot, properly dealing with the roles, and call setData on the other models with the other role. This prevents the loops.
For controls that are not QAbstractItemViews, implement two signals: one emitted on any change, another one emitted only on changes based on keyboard/mouse input. This is the interface exposed by QAbstractButton, for example: the toggled(bool) signal is the former, the clicked() is the latter. You then only connect to the input-based signals.
Your own code must propagate programmatic changes to all the interlinked controls, since changing one control from your code won't modify the others. This should not be a problem, since well designed code should encapsulate the implementation details of UI controls from rest of the code. Your dialog/window class will thus expose its properties in a way that's not coupled to the number of controls showing a particular property.
Hackish Let's-Hope-They-Won't-Become Idioms
Use a flag inhibiting signal emission (Bartosz's answer).
Break the signal/slot connections for the duration of the change (Bartosz's answer).
Use QObject::blockSignals().
There are two possible solutions I can think of:
add a flag which makes possible to ignore particular signals:
void MyListWidget::OnSystemSelectionChanged(QObject *sender)
{
if (sender == this || inhibitSelectionChanged)
return;
this->inhibitSelectionChanged = true;
this->SetSelection(System::Instance()->GetSelectedObjects());
this->inhibitSelectionChanged = false;
}
disconnect the slot from the signal, and reconnect it after changing the selection:
void MyListWidget::OnSystemSelectionChanged(QObject *sender)
{
if (sender == this)
return;
this->disconnect(SIGNAL(SelectionChanged()));
this->SetSelection(System::Instance()->GetSelectedObjects());
this->connect(
this, SIGNAL(SelectionChanged()),
this, SLOT(OnSystemSelectionChanged(QObject*)));
}
I found my solution in QObject::blockSignals() method. It will prevent emitting signals from the list widget while I am setting selected items.
Thanks for all the answers and solutions especialy for BartoszKP's. This solution is looks like the official way of his first solution.
The problem: you've tried to cut corners and created a singleton. Not a classic case for singleton.
Signals and slots are used for notifications, each object notifies interested objects about what it did or to reflect its new state.
I'm suggesting changing the design as follows:
No singleton signal.
Each Object has its own signal and slot for a relevant event (e.g. selection change).
The application or a higher level object (that created the widgets/objects) performs the signal to slot connection. If those widgets are placed in a list, this is very simple.
Related
So when I use a setText() on a QLabel for example, Qt automatically updates the view/gui for me and the new text is shown, but what happens behind the scenes? Is there an update function that gets called automatically when using functions like setText()?
Thanks!!
You should check the basic documentation in this link.
The internal system is a little bit more complex but in general, it follows the observer pattern. This mechanism allows the detection of a user action or changing state, and respond to this action.
Low-level interactions, like refreshing the screen are implemented via the Event System
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, regarding the display process, there is a dedicated event. A QWidget object handles/subscribe to a PaintEvent, see QWidget::paintEvent.
This event handler can be reimplemented in a subclass to receive paint events passed in event. A paint event is a request to repaint all or part of a widget.
When you call, QLineEdit::setText(), the widget will be repainted the next time a display event is triggered, based in the OS configuration, refresh rate, etc.
For high-level interactions, Qt uses a similar pattern based in the signal/slot mechanism:
Observer pattern is used everywhere in GUI applications and often leads to some boilerplate code. Qt was created with the idea of removing this boilerplate code and providing a nice and clean syntax, and the signal and slots mechanism is the answer.
I have a MainWindow class in Qt, in which several checkable QGroupBox widgets are placed.
What I want to do is, to trigger a general onClick(bool checked) slot whenever one (any) of the QGroupBox objects are clicked, identify the sender and trigger some code.
I need to capture the objects' "clicked" signal in order to prevent a disabling action it performs on its children when the control is clicked.
This is the signal I'm trying to handle:
class Q_WIDGETS_EXPORT QGroupBox : public QWidget
{
...
Q_SIGNALS:
void clicked(bool checked = false);
...
};
I tried adding a custom slot like this and tried connecting it with the signal above but since QGroupBox at its own is not an object or pointer, the operation fails.
void MainWindow::onClick(bool clicked)
{
qDebug()<<"Custom slot triggered";
}
Long story short, I need to handle a control type's default behavior within my MainWindow class.
Thanks for any ideas in advance.
I need to capture the objects' "clicked" signal in order to prevent a disabling action it performs on its children when the control is clicked.
Perhaps, but I'm smelling an XY Problem here. You can certainly prevent emission of signals by invoking blockSignals() on the widget. But that's a hack - it will also prevent Qt's internals from acting on the object's destroyed() signal, and you might subtly break other users of the object's signals.
Instead, one could make the UI stateful and have the controller implement the stateful aspect of the button's interaction with the rest of the application. Currently, the button's clicked() signal is connected directly to other users. Instead, connect the button to the controller, and have the controller disable the children only when it's appropriate to do so. One could use the QStateMachine to make this stateful behavior explicit in terms of states.
#Kuba Ober, maybe you're right, I could not state my problem and the facts around it seperately and clearly. Thank you for pointing that out.
After checking out the QGroupBox class' source, I discovered that a "toggle" signal is emitted after every other operation in a "clicked" event.
http://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/widgets/qgroupbox.cpp
void QGroupBox::setChecked(bool b)
{
Q_D(QGroupBox);
if (d->checkable && b != d->checked) {
update();
d->checked = b;
d->_q_setChildrenEnabled(b);
#ifndef QT_NO_ACCESSIBILITY
QAccessible::State st;
st.checked = true;
QAccessibleStateChangeEvent e(this, st);
QAccessible::updateAccessibility(&e);
#endif
emit toggled(b);
}
}
By combining this information with that of #rbaleksandar 's suggestion, I managed to obtain a solution.
I iterated through the controls of my MainWindow class and connected every QGroupBox's "toggle" signal with a common "MainWindow::onToggle" slot in which I could handle the post-event operations I desire.
As for my previous approach, I could've created a class which inherits QGroupBox and override any methods I wish to. But that would be overkill compared to my current solution. The fix I've came up with did the trick perfectly.
Thanks everyone for their insight and help.
I have a small Qt plotting application and I am enabling/disabling widgets (combo/spin boxes) based on a "master" combo box. For example, say the master is combo1, which changes the entries in combo2, based on currentIndex(), enables/disables spin1, and sets a value for spin1 if a certain entry in combo1 is selected. There are more widgets than only these, though.
After the small discussion in the chat (and onwards), I used Qt::QueuedConnection with every connect(), but this didn't stop the re-enabled widgets to emit signals when re-enabled. This caused my many connect() to all be executed for all the re-enabled widgets, resulting in multiple plottings, which I want to avoid. As they are right now, (almost) all the widgets use plot() inside a connect(), so it's multiple signals to one slot.
My question: is there a way to prevent emitting the signals when the widgets are re-enabled? I could make plot() use some bool to check whether the plot has been executed and prevent further actions of the same type, but that would still cause the widgets to emit the signal and run plot(), even if the check will prevent the actual plotting, but that doesn't seem like the way to go. I would also prefer to avoid running installEventFilter(), or similar, as that would, most probably, slow down even more than the previous fix.
Another option, already mentioned in a comment, is to use QObject::blockSignals:
combo1->blockSignals(true);
// do what ever you need
combo1->blockSignals(false);
I find it easier to use and read. Also, there are many situations where you simply don't know / handle the connections.
Update
Since Qt 5.3 you also have QSignalBlocker, an exception-safe wrapper for blockSignals (internally it uses RAII to block signals in the constructor and restore them to their previous state on destruction):
{
QSignalBlocker blocker{combo1}
// do what ever you need
}
Use disconnect before every connect to prevent multiple connections. Disconnecting a not connected slot is always allowed.
disconnect(spinbox1,...);
connect(spinbox1,...);
Blocking signals is also possible but I think you want the first solution.
From QtDocumentation:
bool QObject::blockSignals(bool block)
If block is true, signals emitted by this object are blocked (i.e., emitting a signal will not invoke anything connected to it). If block is false, no such blocking will occur.
I have a combo which is disabled, but adding an element to it will emit the currentIndexChanged(int) signal.
I expected signals to be naturally turned off when a widget is disabled, but it's not the case. I know there is blockSignals(bool), but if there are many widgets whose signals must be "blocked when disabled", blockSignals would require a Boolean state for each widget.
How can I disable the signals sent by a widget when it is disabled (and not alter its blockSignals state)?
EDIT
To clarify: since this is a widget, user cannot interact with it when it's disabled, but some signals are emitted when altering the widget programmatically. In my case there are two interesting signals:
currentIndexChanged(int) and activated(int)
The problem in my code is that I sometimes alter the combo programmatically AND I wish it to emit a signal, and sometimes it's the user that alters the combo by interacting. That's why I am using currentIndexChanged and not activated.
In both cases, anyway, I don't want the signals to be emitted when widget is disabled.
The QComboBox signals are user interaction based from end user point of view if you only have a QComboBox and nothing else as your question seems to imply.
I simply cannot reproduce the issue. I have just made a short program where I cannot get any of the QComboBox signals emitted since I cannot simply interact with the widget.
Edit: It might be a good idea to upate your question with more context for the casual readers, but based on further clarification in comments, yes, programatically it might be the case, but then signals might be useful to process programmatically, too, with corresponding slots, so it is not a major improvement if Qt blocks them automatically.
Luckily, the feature you wish to have is already available:
bool QObject::blockSignals(bool block)
If block is true, signals emitted by this object are blocked (i.e., emitting a signal will not invoke anything connected to it). If block is false, no such blocking will occur.
The return value is the previous value of signalsBlocked().
Note that the destroyed() signal will be emitted even if the signals for this object have been blocked.
If you want to do it for many widgets, create a simple function that you call instead of myWidget->setDisabled(true);:
inline bool disableAndBlockSignals(QWidget *widget)
{
widget->setDisabled(true);
return widget->blockSignals(true);
}
If you want to disable only some of them, say, currentIndexChanged, you can use disconnect manually then.
You can disconnect signals with the QObject::disconnect(); when you want to block them and then reconnecting them when you want to unblock them.
In your case, the signals are the sole source of state information carried on to other objects. If you disable them, the other objects won't ever get any notification that the state was changed. This can cause bugs in the objects that depend on being informed of your widget's state.
There are at least two solutions:
Don't change the widget's state. You can certainly defer the update of the widget's contents until after it gets reenabled.
Create a proxy that monitors the originating widget's state, and queues up the signals (with compression) until the widget gets reenabled.
Due to those workarounds, your design may require a rework. Perhaps it'd be better if you could cope with signals from those disabled widgets. You should also evaluate whether disabling a widget doesn't break the user experience. What if the user wants to see the contents of a widget, but doesn't mean to change the current setting? A disabled widget in such a case is going too far. You can make you own, perhaps subclassed, widget, acting so that the control is not disabled, but the current element stays fixed. This could even be a separate object, applicable to any control - through judicious leverage of the user property.
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).