I have a model Tree of different POJOs containing several JavaFX Property<?> properties.
I was now wondering on how to attach a ChangeListener to the top of the tree which is fired every time something in the object tree changes.
I experimented a lot with custom Bindings and Invalidations but I think I am missing something here.
The background here is, that I want to detect if the model needs to be saved or not. And I do not want to attach a change listener to every single property in that tree. There must be a better way.
Related
I have a set of QML items distributed all over my UI. They display data from a remote device and their content needs to be updated regularly. The Items are spread on several tabs and hidden in nested ListView instances, so most of them won't be visible to the user all the time.
In order to keep the bandwidth low I want to update only those items that are currently visible to the user.
I am looking for the right hook to get the information which of these Items is currently displayed from within the Item, without relying on information from the parents. If they were all placed in ListView delegates I could use the delegate's Components onCompleted and onDestroyed signals. Since this is not the case I am stuck at finding out how to get this information.
Am I missing something here? Is there an onPaintFinished signal or something similar? My workaround would be to add that logic to the parent containers, but that would be tedious, since there are several kinds of container that can contains these display Items.
Instances that are on delegates of a ListView will not exist until they would be in the visible range or the cache range around the visual area of the list view. If the delegate moves outside of that range, it is destroyed. So, no need to worry about instances hidden there.
Furthermore, items are currently not visible are also not drawn. They are not entered into the scene graph, and hence, not rendered. So, instances of your items appearing on tabs that are currently not current will also not be drawn. However, these items do still exist of course.
Figuring out if an item is effectively visible or not is quite a hard problem though. QML delegates part of that to OpenGL (clipping for instance). There is not feedback on the result of that. You could in theory lift that information out of the renderer, but that would require customizing that and that is very hard. You could take a look at the heuristics that GammaRay uses to warn about items not being visible. Perhaps you can take some inspiration from that.
What would be the preferred (recommended) way to rearrange the components of a QML UI on an event such as a button click?
I do have designed a UI consisting of a bunch of custom components, each of them is bound to a (C++) model. I use anchors to position the components in the ApplicationWindow.
On a button click, I want to add an additional component which, due to its size, makes it necessary to rearrange the existing components. Actually, the button could be understood as switching into a different mode such as the Debug view in an IDE (think of Eclipse).
My goal is to keep the components in a consistent state between views and make the switch as fluent as possible.
I could think of these options:
Design two different views, and use a Loader or State to switch between them. As initializing the models takes some time, they should remain not be deleted during switching. I think, setting them as ContextProperty of the QMLApplicationEngine should take care of that.
Do a lot of rearranging in the onClicked()-Handler of the button. Probably the worst solution but does not require to reinitialize the components and models.
I think the most elegant solution would be to initialize the components in a some kind of container (or model) and then assign different layouts to this container on button click. But I have no idea, if this is possible and how to achieve that.
Edit: I followed approach 1. by using the StackLayout. It works basically, but it seems as if the invisible UI is still running in the background and consuming resources (e.g. requesting Images from my QQuickImageProvider).
Using a Loader eliminates this problem as it destroys the previous UI on every change of the source property. What I do like about the StackLayout however is that it preloads all UIs on app startup. So the transitions are smoother compared to the Loader. Is there a way to disable the invisible UIs?
Your option (1) is the one giving your the most flexibility, since you have two entirely separate UIs depending on state.
As you already discovered yourself this requires keeping all relevant state data in a way that is accessible by both UIs, e.g. in C++ or in globally accessible QML/Script objects.
I would go for that if you envision any more changes or tweaks than just rearranging elements.
If you are sure that rearranging elements will be sufficient, have a look at QML states
It is a bit like a combination of your options (2) and (3).
The state setup allows you very locally to define anchors and other properties for each element depending on a named state.
The button's signal handler then only needs to change which of the states is active, by assigning one of the names to the respective state property.
Can anyone clarify this statement from the WatchKit Development Tips page?
Simplify controller scenes.
Reduce the number of hidden objects as much as possible to significantly improve load time. For example, five versions of a controller’s layout in a single controller scene will result in all objects being created before the controller is displayed
I've read it a few dozen times now and can't figure out what it's trying to say.
What is a "scene"? Is it referring to the Storyboard scene?
Are "hidden objects" referring to literally hidden UI elements like a hidden button?
How is it possible to have five versions of a controller's layout? This just does not compute.
When a storyboard is loaded, and there are, say, 10 different WKInterfaceControllers in the file, will that be very slow even if the initial controller is blank? Aren't these only loaded as-needed? Or, would it be better to have a single table with 10 prototype rows - each of which is actually a stand-alone interface - which are only instantiated one at a time?
Because we can't programmatically add interface elements to controllers in the current version of WatchKit, any interface elements that we might need to display must be included in a Storyboard scene. By including these initially-hidden elements, we can programmatically hide or unhide these elements as needed.
For example, it's common to include a full-screen label that is initially hidden. Then, if a full-screen message needs to be shown for some reason, the text is populated, the label is unhidden, and the rest of the elements on the screen are hidden. To make hiding a set of elements easier, they're typically included in a WKInterfaceGroup, so that only the top-level group element needs to be hidden.
So, to answer your questions:
Indeed, a "scene" is a standard Storyboard scene.
Yes, "hidden objects" is referring to literally hidden objects as I've described above.
Using the method I've described, you could create five top-level WKInterfaceGroup elements, each with its own set of controls and layout. Then, you'd likely unhide the one that makes sense to display and hide all the others.
I use these techniques in my own app, though I typically don't have more than three top-level groups.
So yes, because it takes time to initialize and layout all of these elements (even if they're hidden), the recommendation is to keep it to a minimum.
Regarding the loading of interface controllers in a storyboard, you're correct that only the interface controllers that are needed are loaded. However, if you have a set of five page-based controllers, they'll all be loaded and initialized before the first page is activated. Other controllers would then be loaded as appropriate.
Creating unique rows is another possibility, but whether you do that or simply hide/unhide top-level groups depends on your app's specific needs. As always, it's worth testing on actual hardware.
I'm refactoring some Flex code written by another developer and I'm implementing a PresentationModel approach, as I like to separate out the ActionScript from the MXML. One of the problems I've found is that the original ActionScript code adds/removes elements from the MXML.
What happens is the handler function checks the model and if the values are correct will either create or remove a element from the view. What is the best way to get the presentation model to ad elements to the view and still keep this loose coupling that I'm aiming for.
I was thinking of using simple events which the presentation model dispatches and a view can list for passing the details of the element to add. Is there another solution?
Thanks
Stephen
If you're using the presentation model, I'd assume that you have some kind of data of what needs to happen. When items of any sort are being dynamically added/removed, I make sure to make it data-driven for easier manipulation. If you want another item added, add another data model to your dataProvider of choice (List, ComboBox, DataGroup, etc).
By doing this approach, you're abstracting the logic from the presenter to the view. Events should only be used as a way for your view to know when your presenter has accomplished something. Data can be received this way (and it's good practice to do so) OR you can just bind the data within the presenter to your dataProvider. Both are good, I just find binding to be cleaner and simpler.
Every part of code that do some graphical stuff (drawing border, setting style, drag & drop management, animations, ...), should be included in the view, not the presentation model.
For this kind of graphical that stuff should be executed after a property has been changed in the PM, we use the Cairngorm 3 Observer lib. Basically, it listens to some changes in the presentation model and allows you to execute a function in the View.
<cg:ObserveValue
source="{ model.firstName }" value="{ Name.SARA }"
handler="runEffectFunction"/>
See the documentation
I have an actionscript-instantiated component in a containment hierarchy; it extends ComboBox, but it's instantiated dynamically--you never know when you're going to need it.
Somewhere up in its containment hierarchy, there's a thing which extends NavigatorContent which logically is the right place to put the valid values for said combo box.
What's the canonical way for that child component to get a reference to that set of valid values?
I would solve this by having the child dispatch a bubbling event (CHILD_CREATED) with a self refrence when it's created. Then simply listen for the CHILD_CREATED event in the object that has access to the set of valid values.
#1 Parent is created - add a listener to know when a child is created and needs a refrence to values
#2 Child is created - dispatches CHILD_CREATED dynamic event with a self refrence as a property
#3 Parent hears CHILD_CREATED - extracts the reference to the child component and sets its data provider to the set of valid values.
EDIT:
A much cleaner way to handle this kind of problem if you are dealing with a component based on DataGroup is to use the rendererAdd (there is a refrence to the renderer in the event). This would definitly be the canonical way to handle it.
So if you are using a DataGroup to display components that you need to access directly, just use the rendererAdd event. If that issn't applicable to your problem, I'd go with the CHILD_CREATED method.
I don't think there is one canonical way to solve this. There are so many possible solutions. You could:
Pass the values as an argument to the child constructor
Pass a reference to the NavigatorContent and then get the values directly upon instantiation
Pass a reference to the NavigatorContent and then add a change listener to it, which fires every time a new value is set
Use a Factory or Factory Method which has a reference to the NavigatorContent to create and populate the child
Create a Proxy or Delegate class to manage creation and data population of all children of the NavigatorContent
...
I'm sure there are tons more.
It all depends on what your program is doing, how the rest of the hierarchy works together, when and if those values are updated, and whatever other requirements need to be fulfilled.
Start from there, then look at the suggestions people have made here, and pick one which suits your scenario best.