I need to listen for changes in the Qt3D scene tree (node added, removed, property changed, etc...).
I found class QSceneChange but documentation is missing and I can't find a usage example.
How to use this class to watch for node create/destroy events?
I know this question is a bit old (and maybe you have already found an answer) but I'll try to shed some light on this issue:
You can listen for changes on the nodes you created. I.e. when you add a QNode you can connect its signals to your implemented slots. The following signals are available:
Node removed: nodeDestroyed()
Parent changed (i.e. the node was set to a different parent): parentChanged()
These two signals are emitted by QNode, and thus, all the inheriting classes. There is no Node added signal because you know when you created nodes and add them to the framegraph. All framegraph classes inherit from QNode so they emit those signals (QEntity, QAttribute, ...).
All other signals depend on the respective inheriting class and are thus emitted by them.
For example, if you want to listen to changes in the properties of a QAttribute you have to connect slots to the signals of that class. You can see such a list here.
Some more explanation:
The QSceneChange is not meant for you but for the back-end. Qt3D uses a front-end - back-end scheme where you use front-end nodes like QEntity or QAttribute or whatever - i.e. all classes inheriting QNode are front-end nodes (see the "Inherited By:" section in the link).
When you visit their GitHub repo and look for example at the render folder, you see that there's a backend and a frontend folder.
The frontend folder holds all the Q-classes, like QEntity and so on. The backend folder holds the corresponding back-end nodes, Entity in this case. I'm not sure why they didn't separate everything properly but if you check out the framegraph folder you'll see the same pattern again - some classes starting with a Q and the corresponding classes without the Q.
Now, the front-end notifies the back-end about changes in its nodes using QSceneChange so that the back-end can act accordingly. The creators of Qt3D probably thought it not necessary to have a signal that notifies you about all changes. most of the time you would want to subscribe to one specific property changed event, like byteStrideChanged() in QAttribute (Why would you want to react to each and every change?).
I assume you could somehow intercept those QSceneChange events (new implementation of QNode or something like that) but they are not meant for you.
Related
I made this post on the Qt Forum as well but I haven't gotten any follow up so I'm hoping to continue the discussion some here. Here is the relevant parts of my post and the response.
My Post:
I have the following design: A main window which has a widget, and
inside that widget different widgets of type "Page" can be loaded. The
first page, let's call it the startup page, allows the user to type in
the serial number of the product. The database is then queried to get
some info about the product itself, and then a concrete child class
representing the type of "Product" is created. All child product
classes inherit from an abstract class, Product.
Basically, when the user selects the product by entering a serial
number, a product factory is called to create the concrete object and
then check if it's physically connected to the system via a bus. This
created product will then be passed to and used by other pages in
somewhat of a wizard like fashion.
Response:
The biggest problem I see [...] is that the ui
is kinda driving your logic. Typically that's a bad idea and down the
line leads to problems that are hard to foresee in the planning stage.
The way I would approach it is that your app is a state machine.
There's user input stage, product lookup stage (which may fail from
what you describe), product view/editing stage etc. Transitions
between those stages would dictate a ui change, for example switching
from product id input to product lookup would switch ui page from
input form to a wait indicator and finishing the query would move
either to success or fail state, which would show an error page or the
product page accordingly. The product object would then be governed by
the state machine state that handles it. Lookup would produce an
object and pass it to the view/edit state and that state would free it
when transitioning to another state. Your logic would be better
encapsulated this way and independent of the ui, which you may want to
change someday or make optional e.g. drive the state machine in a
silent mode, app params or something else. The ui would just send a
signal that would change the machine state e.g. entering a number
would transition the machine from input to lookup, which in turn could
be connected to page change.
The issue I'm having here is I'm not seeing how this actually decouples my application logic from my UI? The QStateMachine would be configured to transition between states based on button clicks which is inherently coupling it to my UI. If I wanted some type of "headless" mode, I'd basically have to reconfigure my entire state machine to attach to signals from different objects. I suppose I could try to abstract this by having a builder type class that configures all the state transitions based on what mode I'm in.
Maybe this indicates I would need some sort of intermediate object which is used whether or not I have a UI, and the state machine connects to signals from that object instead. My different widgets would then contain a reference to this same object and utilize it.
Basically, I am asking how I can decouple my state machine from the UI when it seems it's coupled by design, since what's driving the state machine is the UI itself.
The QStateMachine class and its related classes are not coupled “by design” to the UI. They could be used to implement state machines in any layer of the app.
The response you received just advocates for a better separation of concerns.
Like you already said (about the “headless” mode), you can pack your business logic in a component that drives such a state machine to handle the flow of your process. You can of course have also other state machines, in the UI, to handle model updates, user interaction and page navigation.
I struggle finding the right way to mutate my state in an ngrx application as the state is rather complex and depending on many factors. This Question is not about doing one piece of code correct but more about how to design such a software in general, what are doe's and don'ts when finding some hacky solutions and workarounds.
The app 'evolved' by time and i wan't to share this process in an abstracted way to make my point clear:
Stage 1
State contains Entities. Those represent nodes in a tree and are linked by ids. Modifying or adding an entity requires a check about the type of nodes the new/modified ones should be connected with. Also it might be that upon modifying a node, other nodes had to be updated.
The solution was: create functions that do the job. Call them right in the reducer so everything is always up to date and synchronus when used (there are services that might modify state).
Stage 2
A configuration is added to the state having an impact on the way the automatically modifyed nodes are modifyed/created. This configuration is saved in it's own state right under the root state.
The solution:
1) Modify the actions to also take the required data from the configuration.
2) Modify the places where the actions are created/dispatched (add some ugly
this.state.select(fromRoot.getX)
.first()
.(subscribe(element => {this.state.dispatch(new Action({...old_payload, newPayload: element}))})
wrapper around the dispatch-calls)
3) modify the functions doing the node-modification and
4) adding the argument-passing to the function calls inside the reducer
Stage 3
Now i'am asked to again add another configuration to the process, also retrived by the backend and also saved in another state right under the root state
State now looks like:
root
|__nodes
|__config_1
|__config_2
i was just about to repeat the steps as in stage 2 but the actions get really ig with all the data passed in and functions have to carry around a lot of data. This seems to be wrong, when i actually dispatch the action on the state containing all the needed info.
How can i handle this correct?
Some ideasi already had:
use Effects: they are able to get everything from state they need and can create everything - so i only need to dispatch an action with only the actions payload, the effect then can grab everything from the state it needs. I don't like this idea because it triggers asynchronus tasks to modify the state and add not-state-changing actions.
use a service: with a service holding state it would be much like with effects but without using actions to just create asynchronus calls which then dispatch the actions that relly change state.
do all the stuffi n the component: at the moment the components are kept pretty simple when it comes to changing state as i prefer the idea that actions carry as little data as possible, since reducers can access the state to get theyr data - but this is where the problem occus, this time i can't get hands on the data i need.
When looking through the main app bootstrapper, the InjectionProxy is used to register instances and interfaces. I noticed that interfaces can be registered as InstanceType.SingleInstance (done for the database in the Tesla app) or InstanceType.EachResolve. Further delving of the InjectionProxy code shows that instances are always SingleInstance.
What is the difference between SingleInstance and EachResolve, why would I choose my interfaces to be one or the other, and why are instances always set to be SingleIstance?
SingleInstance means that it will only ever create one copy of the class, for use in anything that requests it.
EachResolve, means that each class that has this interface injected into it, will get a new instance of the interface.
It depends on what you want for your app. In most cases, SingleInstance is what you want, but EachResolve is there incase your situation requires a new instance, instead of the same one used throughout your app.
I am learning pureMVC and trying to implement the framework into one of my application. I have follwing case:
My main application has Canvas which is used to add different kind of custom components. One of the custom component is a "Search Component" (multiple instances are created on page). My search component has a textfiled and a search button and initiate search in following steps:
1-Clicking search button dispatches a custom event, that custom event keeps reference of search component as a property.
2-My AppMediator listens the custom event and get the reference of current search component along with search text.
3-Mediator send a notification (sentNotification(AppConstants.SEARCH_CLICKED, component)).
4-I have registered a command with SEARCH_CLICKED notification.
5-Command retrieve a WebserviceProxy and invokes its Search(text) method.
6-WebserviceProxy talks to remote webservice and uses asyncToken to get results.
My Questions is:
My Command has the reference to the custom search component when it start search but search webservice takes some time and get the result. How can i handle the results back to custom search component that initiated the search. Since i have multiple instances of search component. What is the best place to keep the reference of that component, should i add a variables in WebserviceProxy to keep that reference and hand the results over to it, or i have to create a Global Proxy to keep references of such components?
Thanks
I have been using PureMVC for some years and I like it!
I think you have not yet understood roles and collaboration of main components.
You should not have any dependencies between Commands and UI-elements. Your Mediator has to get the concrete value from your UI-component and send it through the Notification. In this case the Command and the Proxy will get only a text value and it is no matter, what is the source of it! Suppose you will change your UI after some time and you will have another components on the user side to determine the search value. In your case you would have to change the Proxy and the Command. It would be bad.
Proxy may not have any information about Commands and Mediators. It can only offer its functions to let another components interact with it AND it sends Notifications with new information after getting it without knowing who is interesting in it.
Read the description of the framework once more and write your questions.
I had some problems with understanding the stuff too, I see your problem.
Based on Anton's answer, i re-think and tried to separate dependencis. As a result, i tried to mediate each instance of Search Widget with "SearchMediator" separately by providing different ID to the constructor of Mediator. Now, when search widget intiates a new search, it's mediator invokes the Command, Command invokes a method of Proxy to do actual search and fetch results from DB and sends a Notification. SearchMediator takes care about that notification and hands over the results to appropriate UI.
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.