JavaFX Scene Graph modification for Responsiveness Indicator - java

It is bad practice to do big jobs on the UI thread as if you do, those big jobs will cause the program to hang (not accept user input or render any new data) until that job is finished.
I am looking to add a widget to our code base that will indicate to developers when they have committed this taboo. My idea, and one I've seen on a number of other applications, is to have some component that is constantly moving at a constant speed, such as a bar that is constantly twirling on the screen. With such a tool, if a developer is working and accidentally does something that is more computationally difficult than he expected on the UI thread, this spinning bar will become choppy, indicating to him, when he does functional testing, that he needs to implement mechanisms that will cause this job to be executed elsewhere.
One odd requirement on this code is that it should be completely non-existent in production builds, and only present in dev builds, since it is a widget not for users, but for developers.
I jumped into the Canvas objects and wrote up a quick component that simply spins a teal bar. The idea is that if a big job is dumped on the UI thread, the bar will stop spinning (since the FX job queue wont continue dispatching) and the bar will jump forward, rather than rotate smoothly (as it does when the program is at rest).
Below is a screen-shot of this first implementation:
(notice the teal bars, which, if you saw our application running, would be rotating slowly but steadily --hopefully anyways)
The issue here (as you might notice) is that our layout's been screwed up. This is because I'm modifying the scene graph from this:
Scene
RootComponent
Content
to
Scene
obnoxiousPane
Canvas
Spinner(s)
RootComponent
Content
Modifying the scene graph in such a way has things like preferred height, mouse events and (presumably) any number of other events getting dispatched to the spinners rather than the content components.
Of course, when we go to production, I would like to have the original scene graph in the version that we give to our users.
So my question is this: How should I go about correcting these problems?
I could go after each of them individually as they come up, writing a lot of custom code to do things like
obnoxiousPane.prefHeightProperty().bind(content.prefHeightProperty)
obnoxiousPane.prefWidthProperty()//...
spinner.setMouseTransparent(true)
spinner.setOtherEventsIProbablyCantEnumerateWithoutSeriousResearchTransparent(true)
Or I could try to go after this problem with reflection, attempting to bind every property in the content pane to the corresponding obnoxiousPane property, but this seems like a bug breeding ground.
Or... what? I'm hoping there's some LightWeight component or ImNotReallyHereProperty that I can leverage to add this development aid.
Thanks for any help!

Your approach seems fundamentally flawed. You shouldn't be stalling the JavaFX application thread.
Instead you should have a concurrent process and update the UI as appropriate as the process starts, progresses and completes.
See this java2s sample for using the JavaFX concurrency and progress indicator facilities for an example of such an alternate approach.
If you want to disable some portion of the UI for a time, nodes have a disabled property which you can set. You can use CSS to style a disabled node so the user has some indication that the thing hasn't just hung and is deliberately disabled.

Related

How to implement lazy rendering/pagination for an Android TextView

I have an Android app that offers syntax highlighting for source code files. It's performing very poorly for large files such as this and freezing the UI for 10+ seconds. I have profiled my app and a method out of my control appears to be taking up a lot of time on the main thread. I would like to implement lazy rendering / 'pagination' so that instead of coloring the whole file when the user loads it, I only color what the user sees at first, and color in uniformly-sized chunks as (s)he scrolls down. What are some approaches I can take to implementing this? Thanks.

JavaFX UI elements hover style not rendering correctly after resizing application window

At times, certain UI elements that have a hover style will not render at all and a white box is left in it's place. This only happens after I resize the application window and when the UI element is completely outside of the original bounds of the application window. The button shown in the images below also does not immediately render correctly after removing the mouse pointer from the hover position, so the issue likely would occur whenever the button needs to be repainted.
"Device Logging" button is being hovered by the mouse, before resizing the window.
After resizing the window. Both the "Device Logging" and "Misc Tests" buttons are 100% outside of the original bounds of the window. The "Cloud Server Migration" button however is still rendering correctly.
I have set styles, but removing them has no effect. The issue only seems to appear when there is other processing taking place, such as running the firmware update function. That tells me that there may be something taking up UI time, but I would have expected that to affect every UI element, not just certain ones.
One other note, the UI was converted from Swing to JavaFX, so all of the threading did not include the use of Task or Platform.runlater(). I have since made sure all UI updates are using Platform.runlater(), but I have not yet converted all of the original threads that don't update the UI to Tasks. Below I am including the framework of running a firmware update.
Edit: Was able to reproduce the issue without starting a firmware update, so I don't think it has anything to do with processing blocking UI rendering. The issue occurred only after using some of the UI. As such I removed the code that was posted above. This leads me to believe it has more to do with the actual layout of the UI.
I believe I have figured out the issue. I use a ListView to hold an Object and a cellfactory to render each of the cells with a custom UI. When populating the list with items, additional threads are spawned to retrieve information for each Object within the cell. The variables associated with the Object are bound to a view property within the custom UI. I was not using Platform.runlater() to update these properties with the new information. After updating the sets to runlater, the issue appears to have been fixed.

What is causing slow performance in my JTabbedPane-based Swing application?

I have a Swing application for creating RPG characters.
It has a nested JTabbedPane architecture, so there is a HeroTabsPanel which has HeroPanels and each of those has some more tabs like Stats, Items etc.
So the GUI is comprised of the upper tabbed pane for heroes, the lower tabbed pane for current hero tab and an EditViewPanel which displays an EditingView corresponding to each Tab when the tab is selected.
Performance has been bad from the start, but when I added the upper level hero-tabs (to have multiple heroes in editing simultaneously), switching between tabs became even slower.
It takes a few minutes for something to be displayed in the new JFrame after all the code has finished adding components. Could this be the layout?
I am using MigLayout with absolute positioning. Actually, before I added upper tabs, there had been some “Unstable Cyclic Dependency in absolute-linked values!” issues, but now there aren’t somehow.
In stateChanged() I have what amounts to this:
editViewPanel.activateView(currentTab.getLinkedView());
And in activateView():
removeAll();
currentView = heroView;
add(currentView, "pos 0 0");
currentView.refresh();
revalidate();
But like I said, all the code execution is finished in reasonable time, I've done my profiling, but after it is done, there a delay of considerable length, up to a few minutes in the case of first time adding to a new JFrame.
Another issue is that when I need to update a panel within the lower tabbedpane, especially StatsPanel which is made up of string-int elements added for each parameter in a few columns, I get yet another large delay. It also depends on MigLayout and for some reason (bad design, I know) has absolute positioning as well. But I have changed it so that no components are removed/added after initialization, only setText() is used and still there is a big delay after the code is finished executing.
I’m planning to use SwingWorkers but I would like to understand the problem better before I start solving it. I suspect it's simple, but I am a bit incredulous about how big the delays it's causing are. I'd appreciate some hints/examples about SwingWorkers.
I can add more code if you have some general idea where the issue might hide.
Any suggestions are welcome, thanks!
I never encountered a Swing UI which was slow due to the number of JComponents visible. What I do often see is a sluggish UI because the UI thread is used/abused to perform all kinds of work not related to UI updates.
In Swing, there is only one thread on which you may update the UI, and that same thread is responsible for painting the UI (the Event Dispatch Thread). If you block this thread by e.g. performing calculations on it, the UI will not be able to repaint or react on user input while your calculation is running. That is why you must perform all heavy work on a worker thread. This is clearly explained in the Concurrency in Swing tutorial.
Not 100% sure that is what happening in your case, but it definitely sounds like it. If you want to be sure, take a thread dump while you are waiting for your UI and see what the thread named AWT-EventQueue-0 is doing at that moment. If it really takes 5 minutes before your UI is updated, you must be able to locate fairly quickly what is blocking the UI.
Ok, I finally worked it out by going through the EDT dump. The freeze was due to layout, unlikely though it had seemed.
MigLayout was trying to figure out the sizes of all the components every time new tab was selected, and probably for all the components in all the tabs on init.
The solution is simply to override getPreferredSize() for the JTabbedPanel implementation.
#Robin, thanks for the thread dump hint!

Preload a JavaFX stage before show()

In JavaFX I'm switching from one stage to another with stage1.hide(); stage2.show();
However, stage2 is quite big and contains a whole bunch of elements. So when I show() it, when it pops up for the first time, there is a 400-millisecond period of time where the whole stage is empty and grey. Then all the elements appear.
It's horribly ugly. This is on an i7 with a really good GPU.
I have noticed that if I show it, then hide it, then show it again, the final show will look perfect from the moment it appears on screen. However there is a flashing when I hide() then show() the stage for the first time, so that won't work.
Is it somehow possible to achieve what I described in the above paragraph without having to have the stage appear on screen beforehand?
This is on Java 8u5 with the new Modena theme. It is worth noting that with JavaFX 2.2 this issue is not present.
Thankyou!
The root cause of this issue was a performance regression introduced in an early Java 8 release. Updating the Java 8 version to the latest development version, fixed the issue (as reported by the original poster).
After the update, the user no longer experienced: "a 400-millisecond period of time where the whole stage is empty and grey". Therefore the original request in the issue "Preload a JavaFX stage before show()", was no longer required as performance was fine without any preloading tweaks.

How to flush all input events in jMonkey

My game takes around a minute to load in android till the first screen appears. Till the time its loading, jmonkey’s input manager seems to queue all inputs which results in nasty behavior(automatic button clicks) as soon as my first nifty screen loads.
Same happens when the scene loads(which again takes a while on pressing the appropriate nifty button). This happens despite the fact that I set mappings and listeners in the last App State which loads.
Is there a way to flush all previous input which I can call just before and after adding listeners to input manager?
I dont do much work in update() and initialize of my appstates but some functions (reinitialize()) which I call on nifty's OnClick(), loads all the scene and models in the scene garph so it takes a while. Here is a pseudo code of my application
In Main.java {
// Nothing in SimpleUpdate()
// This app state contains
stateManager.attach(new MainMenuAppState());
}
In MainMenuAppState.java implements ScreenController {
initialize() {
niftyDisplay = new NiftyJmeDisplay(app.getAssetManager(), app.getInputManager(), app.getAudioRenderer(), app.getGuiViewPort());
// Create a new nifty GUI object
nifty = niftyDisplay.getNifty();
// attach a couple of more app states which also has nothing significant in update loop
// do some good computation
// attach 5 new APP STATES which does not have anything significant in update()
display the appropriate screen of nifty
}
onClick() {
nifty.gotoScreen(“loadScreen”);
// appstate previously attached. they dont have anything significant in update.
// They have significant initialize methods.
app.enqueue(
rgas.reInitialize(time,cameraLoc,cameraRot);
maes.reInitialize(qId); // loads all the scene and models on screen
nifty.gotoScreen(“hudScreen”);
nifty.getScreen(“hudScreen”).findElementByName(“ConfirmModuleButton”).setFocus();
ppes.reInitialize(); // this contains input mappings
);
}
}
If there is a way to do this it will be on the InputManager so you could check out the API for that. Your problem may be though that the queue isn't really a queue in the way you are thinking. Potentially it is not a queue of input events but a queue of actions being taken in response to the events. Since events don't process until the update loop runs them then if the upload loop is stalled they will keep building up.
You could simply not add the listeners until the application has finished loading, then any events will get ignored automatically. You could also try breaking the scene loading up using a queue or similar of your own to load things a bit at a time while not completely stalling the system.
You may get a better response on this question if you try the jME3 forums. There are more monkeys active there than here including people with more detailed knowledge of the input system than me :)
I guess what Tim B said is your best bet.
However you could try calling nifty.setIgnoreMouseEvents(true) and nifty.setIgnoreKeyboardEvents(true) at some appropriate time to shut-off handling of any events that might reach Nifty and enable it later again.

Categories

Resources