Propagate event to entire object - qt

I just recently started exploring Qt (version 5 at the moment) and I came across an issue to which I could not find any solution:
I would like to send a custom event to the main window such that the event is then propagated to the entire object tree (given by QObject::dumpObjectTree()). Then, certain parts of the object tree can choose to react to the event.
Is there a method to do so in Qt?

What you're looking for (a kind of broadcast event) does not exist in Qt. Events are targeted to specific objects.
Signals are closer to what you want. You can generate a signal without specifying who it's for. Then any other object is able to connect a slot to that signal if it's interested in it.

Related

How to distinguish user edits from data model updates with Qt widgets?

I'm trying to implement MVC in Qt using a data model ported from another platform. I have several widgets onscreen that each listen to the same model to render the data. The user can also interact with these widgets, edit them, and thus push changes back into the model.
The specific problem I have is that if my (ported) data model changes and I push data into eg a QTreeWidgetItem with setData, the widget emits an itemChanged signal. This in turn triggers the controller code that is monitoring user edits, and causes it to push the same data back to the model. Unless I insert data comparison somewhere, I end up with an infinite loop.
Is there some way for the controller to quietly update the item's data without emitting itemChanged? Alternately, is there a better way to distinguish between user edits on a widget and programmatic changes? I am simply listening for itemChanged.
Is there some way for the controller to quietly update the item's data
without emitting itemChanged?
I hope not. I would not like it if I had a view, which shows wrong data because someone secretly changed the model. I am afraid, you have to conjure up something yourself. You have to modify your controller. Not emitting itemChanged when it does.... horrible idea.
I was thinking, what you could do. Expect no complete solution. I just looked around how I would do it. You must subblass your model and override the setData method. Then you can distinguish changes by the role. Qt::EditRole or you can create your own user defined role. The itemChanged signal must be emitted in any case. Else your views would be wrong. But in your model subclass you could implement a new signal 'dataChangedByUser' or whatever, which could be emitted additionally to itemChanged. How your controller handles this....

How do events work in Qt?

I have some questions about the general usage of Qt events. I'm new to Qt, and I am going to try out making a custom event. The questions I ask are related to this article: Qt 4.8: The Event System
When does an event “occur”? In Qt's built in events, mouse clicks and key presses are put into a queue and then the functions are executed at the next frame. I’m especially wondering about this for custom events, because I’m not sure if it always occurs when a mouse is clicked. For custom events, is it when you send the event into the queue and then waits to be processed by the event() function at the next frame?
To create a custom event, must you make a class that inherits from QEvent and register an event with registerEventType() function? Is this the standard process, or can an event simply be a class? How does this function, registerEventType(), work?
Do custom events have a QEvent::Type? Is this the number between 1000 and 6563 that is given when using the registerEventType() function?
What is the recipient of an event? It seems to be in functions' parameters like postEvent(), sendEvent(), etc. However, I am not sure what this object is for.
Where is the actual code that is executed when an event is fired?
Is it a function, or is it in the event() function of QObjects.
Also any working examples of Qt events (both built-in or custom) in action would be helpful.
You should look at Qt Examples online or in QtSDK, there are tons of them.
IMO you didn't search hard.
Ad.1. It occurs after you fire it with QApplication::postEvent() or QApplication::sendEvent(). Not immediately of course, because it has to go through the main loop, etc. The order of events should be preserved, though.
Ad.2. Look at this, second anwser.
Ad.3. Go to Ad.2.
Ad.4. This object will receive this custom event in QObject::customEvent() handler.
Ad.5. Go to Ad.4.

Update a QGraphicsItem whilst a drag is occuring

I'm creating a QGraphicsView-derived widget which, amongst other things, needs to create connections between items in it - a little like a control flow graph. But I am having trouble implementing a method to 'draw' the connections
I've tried two approaches:
Creating a QGraphicsLineItem-derived object when the source object's mouseMoveEvent(..) is fired, and updating it with each subsequent move. The line is drawn and updated successfully, but ultimately this does not work because it seems that moving the mouse 'locks' the event loop into only handling mouse move events, so the other object's hoverEnterEvent(..)/hoverMoveEvent(..)/etc. methods are not called (these are required to finalise the connection).
Creating a QDrag instance in the mouseMoveEvent(..) to create the connection between two objects allows the two objects to form a connection once dropped, but ultimately this does not work because the QDrag::exec() call provides no means for other objects to be notified of the mouse moving - so the drawn connection cannot be updated.
I really need a mix of the two: in a perfect world the QDrag::exec() call would allow other some sort of notification of a mouse move, so I could update the object that represents the connection. Does anybody have a suggestion?
Similar to this question.
I have an open source widget that does this, it is for PyQt, but it may help for what you are looking for.
You can find it in the projexui framework at http://dev.projexsoftware.com/projects/projexui
The code you are looking for is specifically the XNodeWidget class found in projexui/widgets/xnodewidget
Ultimately, I am using the mouse press event to start a connection via the scene and am ignoring the event (based on some sort of trigger - control press or hotspot zone etc.)
Hope that helps!
(an example of what it looks like is the table view on the Orbiter app - http://www.projexsoftware.com/software/orbiter)

How to use QSettings?

If you have a lot of small classes (that are often created and destroyed), and they all depend on the settings, how would you do that?
It would be nice not to have to connect each one to some kind of "settings changed" signal, and even if I did, all the settings will be updated, even those objects whose settings didn't change.
When faced with that myself, I've found it's better to control the save/load settings from a central place. Do you really need to save/load the settings on a regular basis or can you have a master object (likely with a list of the sub-objects) control when savings actually need to be done? Or, worst case, as the objects are created and destroyed have them update an in-memory setting map in the parent collection and save when it thinks it should be saved, rather than child object destruction.
One way of implementing it is given below.
If you wish, the central location for the settings can be a singleton derived from QAbstractItemModel, and you can easily connect the dataChanged(...) signal to various objects as necessary, to receive notifications about changed settings. Those objects can decide whether an applicable setting was changed. By judicious use of helper and shim classes, you can make it very easy to connect your "small classes" with notifications. This would address two issues inherent in the model driven approach to settings.
The possibly large number of subscribers, all receiving notifications about the settings they usually don't care about (the filtering issue).
The extra code needed to connect the subscriber with the item model, and the duplication of information as to what indices of the model are relevant (the selection issue).
Both filtering and selection can be dealt with by a shim class that receives all of the dataChanged notifications, and for each useful index maintains a list of subscribers. Only the slots of the "interested" objects would then be invoked. This class would maintain the list of subscriber-slot pairs on its own, without offering any signals for others to connect to. It'd use invokeMethod or a similar mechanism to invoke the slots.
The selection issue can be dealt with by observing that the subscriber classes will, upon initialization, query the model for initial values of all of the settings that affect their operation - that they are "interested" in. All you need is a temporary proxy model that you create for the duration of the initialization of the subscriber. The proxy model takes the QObject* instance of the caller, and records all of the model indices that were queried (passing them onto the singleton settings model). When the proxy model is finally destroyed at the return from the initialization of the subscriber class, it feeds the information about the model indices for this QObject to the singleton. A single additional call is needed to let the singleton know about the slot to call, but that's just like calling connect().
What I typically do is to create a class handling all my settings, with one instance per thread. To make it quicker to write this class, I implemented a couple of macros that let me define it like this:
L_DECLARE_SETTINGS(LSettingsTest, new QSettings("settings.ini", QSettings::IniFormat))
L_DEFINE_VALUE(QString, string1, QString("string1"))
L_DEFINE_VALUE(QSize, size, QSize(100, 100))
L_DEFINE_VALUE(double, temperature, -1)
L_DEFINE_VALUE(QByteArray, image, QByteArray())
L_END_CLASS
This class can be instantiated once per thread and then used without writing anything to the file. A particular instance of this class, returned from LSettingsTest::notifier(), emits signals when each property changes. If exposed to QML, each property work as regular Qt property and can be assigned, read and used in bindings.
I wrote more info here. This is the GitHub repo where I placed the macros.

howto avoid massive notification in DataBinding

I guess it's quite a common problem in databinding scenarios.
What do you usually do, if you are running a batch update and want to avoid that a propertychanged-dependend calculations/actions/whatever are executed for every single update?
The first thing which usually comes to my mind, is to either introduces a new boolean or unhook/hook the eventhandler, ...
What I don't like about this approaches is:
they introduce new complexity (has to be maintained, ...)
they are error prone, because you have to make sure that a suppressed notifications are sent afterwards
I'm wondering if somebody addressed this problem already in a more convenient way that is more easy to handle?
tia
Martin
Edit: not to missunderstand me. I know about the things .NET provides like RaiseListChangedEvents from BindingList, ... They are all addressing the problem in more/less the same way as I described, but I'm searching for a different way which doesn't have to listed drawbacks.
Maybe I'm on the wrong track, but I though I give it a try here...
There isn't a single one-size-fits-all solution, unfortunately. I've applied or seen the following solutions:
There are two singals. One signal is emitted when the change comes from a user action, the other always fires. This allows to distinguish between changes in the UI and updates by code.
A boolean to protect code
The property event framework stops propagating events automatically when a value didn't really change.
A freeze/thaw method on the signal or the signal manager (i.e. the whole framework)
A way to merge signals into a single one. You can do N updates and they get collected into M signals where M <= N. If you change the same property 100 times, you still only get 1 signal.
Queuing of signals (instead of synchronous execution). The queuing code can then merge signals, too. I've used this with great success in an application that doesn't have a "Save" button. All changes are saved to the database as you make them. When you change a text, the changes are merged over a certain time (namely until the previous DB update returns) and then, they are committed as a single change.
An API to set several values at once; only a single signal is emitted.
The signal framework can send signals at different levels of granularity. Say you have a person with a name. When you change the name, you get two signals: One for the name change and one "instance field changed". So if you only care "has something changed", then you can hook into the instance instead of all the fields.
What platform? The post makes me think .NET.
What is the underlying objects? For example, BindingList<T> as a source allows you to disable notifications by setting RaiseListChangedEvents to false while doing the update.
Other than that (or similar); yes, disconnect the binding during big updates
The easiest route to take is to use the BindingSource component for your data binding. Instead of binding your controls to a particular object (or IList), use that object as the DataSource for the BindingSource, then bind the controls to the BindingSource.
The BindingSource class has SuspendBinding() and ResumeBinding() functions.

Resources