Slow work of EventQueue - java

I have a simple JAVA program with gui that just increments int variable and displays its value in JLabel.
I create new thread for proper(thread-safe) updating JLabel by calling inside it EventQueue.invokeLater() with Runnable class which run method simply does
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
label.setText("" + number);
}
});
When i run program, as expected label's number starts to grow rapidly from 1 to about 5000 but then it starts to slow down and i'm starting to see such label's updates like 100255, 173735, 235678 and big pauses between them with blocked GUI.
But when i compile without using EventQueue.invokeLater(), just calling directly label.setText("" + number); everything works fine and perfect and i can see how each number of my label is changing extremely fast. But of course i realize in that case my method isn't thread-safe.
What's the problem? It seems to me that EventQueue works slow or something.

Probably, the event queue is being choked up. You may want to look at coalescing the events to remove redundant entries when you are queuing event faster than they can be dequeued and actioned.
Every time an event is added to the queue, the existing events are queried to see if they merge the new event with themselves. As the queue backs up, more and more events have to be so queried, and the system gets progressively further behind. This is useful for mouse events, but in a simple (and artificial) case like this it can be detrimental.
Having said that, I vaguely recall that the GUI code is optimized to not attempt coalescing events that don't override the appropriate method, so your problem may be just a simple backlog.
Instead of calling setText directly, you could create a custom event for setting text on a component, implement coalescing for it and use that instead so that at any given time only the most recent text is pending. If you do this and you want to set the text based on what was previously set it's better to retain the value and always set the GUI widget from that rather than recalling the GUI widget's current value with getText. Otherwise merging is much more difficult.

Related

Can I do Swing operations at shutdown time?

This relates to this Java question.
Here's my problem. I've written an app that allows people to do a lot of data entry, typing into a lot of separate fields. To confirm the change in each field they can often hit Return (for a single line field) or control-S (for multi-line fields where Return would be valid input), but that's cumbersome, so I also allowed fields to save their content when they lose focus. So users can type-tab-type and it all goes smoothly.
Except if they change a field and then click on the application window exit X in the corner. They expect that this counts as losing focus and will save that last change. But the lost focus event doesn't happen and the change is lost.
I could add a Done button, which would have the side effect of moving focus and saving the last field, and then exiting. But I shouldn't have to. There's a X in the corner and it should do the right thing.
My first thought was
frame.addWindowListener(new java.awt.event.WindowAdapter() {
#Override
public void windowClosing(.....
because I thought from there I could publish() something to my SwingWorker to tell it call loseFocus on everything. No such luck; publish() is protected.
Basically I need to do one last operation on my various widgets when X is clicked. How do I?
Edit: I should note that each editable widget (dropdown, JTextPane, etc) has been extended to hold the actual relevant data. All the data for that widget, e.g. whether the value the user typed is valid, what it was before he edited it, etc. is in those extended class instances. There's no other place values are held; this isn't model-view-controller.
The reason for this is that widgets can get changed either by user actions or network messages; a message can come in that throws out an existing widget entirely and replaces it with one with new content. In other words, doInBackground is in a permanent read-loop, reading network update messages and publish()ing those update requests to process(). User action happens as usual, between calls to process().
Bottom line,there's no global data structure to go to at exit time to get values. They're all in dozens to hundreds of data structures managed by the swing worker thread.The app itself, outside that swing worker thread, doesn't even know what sort of values and widgets exist - all widgets are created, placed and destroyed by network messages from the server. The rest of the app (what little there is) couldn't safely get to the data if it wanted to, unless I implemented a whole lot of shared data and locking.
It all works flawlessly, and I'd rather not redesign it all for this one tiny shutdown case. It just never occurred to me that I couldn't publish an extra "shut down" message into the work queue for process() from outside that thread. (I mean thread safe queues are trivial to implement; why didn't they?)
If the answer is "you can't talk to swing at shut down", I'll live with it. I do have a potentially evil workaround - I could have x do nothing but send a message to the server, which could write back a "you should shut down message" which could do the rest. But that seems ungainly.
The short answer is, there isn't a good solution. I tried installing a shutdown hook and publishing a message to the swing thread to tell it to finish up, and then gave the shutdown thread a 500ms sleep to give process() time to happen. process() wasn't called. publish() alone apparently isn't enough, once shutdown starts.
Bottom line, don't put data you need to get at in swing threads. Global data and synchronized functions is the only way to go.

How to update a JavaFX GUI correctly while processing data

I'm trying to get into JavaFX for making first attempts in making GUIs with Java. Therefore I made a simple neural network which learns the XOR and displays the output in JavaFX. My question is - how can I update the GUI regularly while processing the data?
Everything I achieved so far is a single update in the GUI when the network finished learning. Even if I started the networking in a thread.
I expect that the right handed side of the GUI updates (circle change the colors in dependence of the output) regularly for each n epoch and not only once. The attached image shows the GUI before the network started.
I appreciate any help in advance.
JavaFX has an "Event Thread", which is responsible for handling button clicks, updating labels, and any other GUI-related tasks. When you call button.setOnAction(e -> doSomething());, when your button is pressed, doSomething() happens on the JavaFX thread. During the time that this is running, no other GUI events can occur. This means your interface will completely freeze, which leads to a bad user experience.
Also, you cannot perform GUI operations on any thread other than the JavaFX thread, or you will get an IllegalStateException. (Try calling Executors.newSingleThreadExecutor().execute(() -> label.setText("hello")); to see this in action)
Luckily, JavaFX provides methods to get around this.
First, and easiest, is to call your long-running method inside a new thread (perhaps with ExecutorServices as above), and when you need to modify the interface, wrap those calls in a call to Platform.runLater(() -> updateInterface());. This will post updateInterface() to the GUI thread, and will allow it to run.
However, this can be messy, so the preferred method is to use a Service.
Assume your long running calculation returns an Double, you create a class extending Service<Double>, override its createTask() method, and perform the calculation there, as such:
public class CalculationService extends Service<Double> {
#Override
protected Task<Double> createTask() {
return new Task<Double>() {
#Override
protected Double call() throws Exception {
return doCalculation();
}
};
}
}
Then, in your controller, declare a private final CalculationService service = new CalculationService();
In your controller's initialize() method, you can then bind the output of this service to anything you want. For example:
calculationDisplayLabel.textProperty().bind(Bindings.createStringBinding(service.valueProperty()));
// continuously updates the label whenever the service calculates a new value
Then, whenever you decide you want to start calculating again, you call service.restart() to interrupt the process if it is running, and start again from the beginning.
If you want to call code when the value changes, add a listener to the value of the service. For example, if you want it to recalculate as soon as it has finished, call:
service.valueProperty().addListener((obs, old, newValue) -> service.restart());
If in doubt, refer to https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Service.html

JavaFX - update label values from other thread

Helo guys!
I am new to JavaFX. I am writing really small application which simulates working of printer. Simulation is running on special thread called PrintingProcess (this process is doing only one thing - waits given time and then increment counter). I need to send this value to window, where labels should show how many pages was "printed". Is any way to do it? So far I wrote small singleton class to hold value.
[edit] I solved it using tasks :) thanks for help
You should use the Task.updateProgress method. Call it to specify the current percentage of pages printed. Override Task.call to perform the action which needs to run in another thread. This method should never manipulate a JavaFX component. You can then oerride methods such as Task.succeeded to implement the behaviour of your UI when the print job is over. Look at the doc of this class to fully take advantage of it.
Platform.runLater(new Runnable() {
#Override public void run() {
textLabel.setText(yourValue);
}
});
The example above is quite simple. You ask JavaFX a runnable as soon as it can. I don't know how that works exactly but that's the way to change UI components from a non-JavaFX thread.
You could pass textLabel variable to any thread with a custom class or a new anonymous thread.
EDIT:
I find Dici's answer more appropriate for your application. I wouldn't recommend putting this code in any loop incase you may still use this.

Java: How to interrupt a program partway through execution with a mouseclick

How would one go about implementing a mouselistener (or some other way, doesn't matter) that will handle a mouse click event at ANY part of the program? Preferably returning to the line it left off at when the click event handler method completes.
I am using swing. The 'context' is a GUI that constantly updates, but must respond to a mouse click from the user at any time with no delay. Indeed I do have experience with events, using and overwriting their handlers etc., not too in-depth I suppose but what i do know has been sufficient in anything until now.
I could not understand your first para, so my answer goes for your second para, if I understood that correctly. ;)
Swing follows single thread model. So, you should be updating the UI from Event Dispatch Thread (EDT). This thread is responsible for delivering the events to your code too, hence the name. If you are continuously updating an UI in a loop then that is going to keep the EDT busy and blocked. The end effect will be an UI which does not respond to user events. This because the events are getting queued and EDT can pick them and deliver them to your code when it becomes free.
Games typically encounter this kind of scenario. You might have noticed that games typically have one fixed rate of refresh which they call FPS (Frames Per Second). Typically maintaining 60 FPS is good enough. That is, you need to draw your UI 50 times per second, but right now it seems that your render loop (which updates the UI) is running continuously.
You need to have separate thread continuously running which is responsible for drawing the UI. This should draw into a buffer (Image). And then invoke repaint() on the UI element to be updated. That UI element's paintComponent() needs to overridden, so that it can copy the image in Image buffer and paint that on the graphics context.
Now comes the real trick. The loop which calls repaint() must do some arithmetic to make sure it does not go beyond drawing 60 times, i.e. looping 60 times, per second. If and when it does then it must call Thread.sleep(sleepTime), where sleepTime is the number of milliseconds left in a second after looping 60 times. It might happen sometime that your loop may take more than a second to complete 60 iterations, then don't just go ahead for next iteration, but call Thread.yield(). This will give other threads a chance to use the CPU, e.g. maybe your EDT. To make the matter more complicated, do not keep yielding always, so might want to put some logic to make sure that yield for only x consecutive times. This last scenario should be very rare, if at all. This scenario means the system is under heavy load.
Remember, repaint() is thread safe and allowed to be called from any thread. It schedules a paint() call on EDT. So, calling repaint() does not guarantee a paint. So, you may want to experiment with different values of FPS to find the one which suites you.
By the way, the trick of rendering to an in-memory Image is technically called Double buffer. This gives us the ability to render nice smooth animations.
Further reading:-
LANSim - Wrote this code a long time back. You can use this code as an example.
http://java.sun.com/docs/books/performance/1st_edition/html/JPSwingThreads.fm.html
Killer Game Programming in Java - This book is on this subject.
Have you looked at SwingWorker? It's a simple framework that lets you run computations in the background and periodically publish updates to the GUI thread.

JFrame not working after first instantiation?

As part of a larger application, I am writing a settings class, which collects and stores user-defined settings. This class is a singleton, and is instantiated during application startup.
In order to accept user input, two different GUI frames are insantiated from within ConfigSettings.java, from a public static method, selectSettings(). Both are subclasses of JFrame. Here is the code for the instantiation of the file selection dialog:
private void selectFile() {
SelectFileGUI fileSelector = new SelectFileGUI();
fileSelector.setVisible(true);
synchronized(this) {
try {
wait();
} catch(Exception e) {
e.printStackTrace();
}
}
fileSelector.dispose();
}
This works fine when the application is initially run. However, at a later point the user may alter their selected settings, including selecting a new source file. This is done by calling selectSettings() again.
The issue I'm having is that any subsequent attempt to instantiate and display these GUI components again results in a new JFrame being displayed, but with a grey background, and no buttons or other components shown. While debugging I was also failing to create new instances of SelectFileGUI directly.
What could be causing this sort of behaviour?
I would check to see if the second time you call it you are using the GUI thread or calling from one of your own threads.
At the top of that method you can test for it (The AWT thread is pretty easily identifiable by name) and have it throw an exception so developers know not to call it on the wrong thread--or you can block their thread and do it in a worker thread.
I don't know what is causing this behavior but in your code the following simply cannot possibly be the right way to manage dialogs (more below):
fileSelector.setVisible(true);
synchronized(this) {
try {
wait();
} catch(Exception e) {
e.printStackTrace();
}
}
fileSelector.dispose();
Do you want your dialogs to be modal or not?
If you want them to be modal, then you simply make a blocking call like when you're invoking JColorChooser.showDialog(...) method and your return "value" is your color/file/whatever.
If you want them non-modal, then you use a callback to get your color/file. In the JColorChooser dialog example, you'd call the createDialog(...) method and use the ok/cancel listeners as callbacks.
I suggest you take a look at sun's tutorial, for example the one on color chooser, to see how to correctly display a modal (or non-modal) dialog:
http://java.sun.com/docs/books/tutorial/uiswing/components/colorchooser.html
Once again, that synchronized(this) { try { wait() ... } to manage something as simple as a file selector/dialog frame just cannot be correct.
Agree with BillK: sounds like you're calling it from outside the EDT first time around (so your call to wait() doesn't block the EDT), then from the EDT the second time around. See SwingUtilities.invokeAndWait() and/or Dialog.setModal().
The consensus here is that you are breaking the rules governing the use of the AWT painting thread (the Event Dispatch Thread).
A couple things to note:
If your code attempts to paint your GUI components outside this painting thread, the gray dialog could be the result of a deadlock between the EDT and the thread your application is using to paint.
If you do get into this situation, you will experience the inability to create new dialogs as described.
However, as you mention that you are debugging while experiencing this problem, it might be that you have paused the EDT through your IDE.
Take a look at this tutorial for some guidelines on how use threads in a client application.
To fully appreciate the issue, it would be nice to see some more code - pertinent parts of selectSettings(), for example.

Categories

Resources