Implementing threading in Swing's EDT? - java

My project is built upon Java's Swing library. It spawns the EDT which displays my GUI (which works correctly).
The entrance to the program, which initializes the EDT:
public final class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Start());
}
class Start implements Runnable {
private Model model = new Model();
private Controller controller = new Controller(model);
private View view = new View(controller);
#Override
public void run() {
// Initialize the view and display its JFrame...
}
}
}
}
However, when a button / radio box / etc. is clicked within my GUI, the Controller class must perform an action on the model.
My questions are the following:
Should I wrap the controller's code in a new SwingWorker?
If no, should I wrap my model's code in a new SwingWorker?
If I wrap the controller's code with threads, do I need to synchronize the shared state variables within my model?
If my model, running on a new thread, notifies my GUI of changes, will this occur on the EDT or on the new thread?
For example:
public class Controller {
public void updateModel() {
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
model.somethingSomethingSomething();
}
}.execute();
}
}
public class Model {
public void somethingSomethingSomething() {
notifyListeners(); // This is going to notify whichever GUI
// is listening to the model.
// Does it have to be wrapped with Swing.invokeLater?
}
}
public class View {
// This function is called when the model notifies its listeners.
public void modelChangedNotifier() {
button.setText("THE MODEL HAS CHANGED"); // Does this occur on the EDT?
}
}

Instead of updating your model from doInBackground(), publish() interim results and update your model from process(), which executes on the EDT. In this example, JTable corresponds to your View and TableModel corresponds to your Model. Note that JTable listens to its own TableModel.

You can read about it here: Improve Application Performance With SwingWorker in Java SE 6. In short: all time consuming operations, which are not affected UI must be done in another thread. To show results of operation you must go back to EDT. For example, if you make database search, you should show a progress bar (usually infinite) and start the search using SwingWorker. To show search results in a table, you must be in EDT. Alternatively you can use foxtrot lib (it allows to make your code more Swing convenient without to redesign it).
If your controller code permanently updates the swing widgets you should execute it in EDT or at least perform these updates of UI in EDT (using SwingUtilities.invokeLater, chunk processing in SwingWorker or swing.Timer).
So your sample is wrong: model update should be up-to-date in EDT.

One alternative approach, from Java Concurrency in Practice 9.4.2, uses a "Split" or a "Shared Data Model". You update your Business Model on whatever thread you want, likely the long-running non-EDT thread. But then, instead of directly calling notifyListeners() and worrying about which thread you are on, simply call myComponent.repaint(), which will queue up a repaint request on the EDT.
Then, somewhere in your paintComponent() method, you explicitly grab all new data from the Model, typically in a method called modelToView()
commentTextArea.setText(myModel.getCommentText());
fooLabel.setText(myModel.getFooText());
...
The upsides are that threading is not an issue, and, at least to some minds, this "makes sense", and the model is nicely decoupled from the view. A downside is that you are resetting all the values every time. So if you have 100 JComponents, that's 100 things getting set. Also, the view is pretty tightly coupled to the model.
Working Code Examples
#MadProgrammer and #kleopatra are correct that, if the view directly contains the components that are being updated, you get an "infinite loop of doom". For proof, see
Demo_14716901_Fails
However, if the view is isolated from the components, you avoid the infinite loop. Normally, the higher level view would contain stuff like JSplitPanes, holding JScrollPanes, holding Boxes or more JPanels, holding the actual low level components. So this requirement, IMO, is not unreasonable.
Working code at Demo_14716901_Works
Some Comments Added for the Downvoters:
Some people want to defeat Swing. They are writing instrument control code or algorithms and just want to get their job done without worrying about the EDT, endless SwingWorkers and invokeLaters. This technique lets them get their job done. With the one important caveat noted, it works. (Personally, I understand and generally like Swing, but many don't).
While Swing components are nicely MVC, they are generally at far too micro a level. The "real" model is not a single String, it is dozens of values. The "real" view is not a single JLabel, it is many JPanels, each with many components, combined with scrollers, splitters, etc. This technique usually fits the real world better, allowing the programmer to think naturally at a higher level.
As far as "bad practice", take it up with Brian Goetz, Josh Bloch, etc. o.k., that's "appeal to authority", but it works for me. :-)

Related

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

How to properly asychronously load UI component using Event Queues in ZK framework?

I have a custom composer/controller class that extends GenericForwardComposer. Inside this class I have some methods that are being used to initialize UI components with data. This is a very long operation and takes time to complete. Due to performance issues I am trying to asynchronously load this data using Event Queues. This way it will not block users from accessing other functions while the process runs in the background.
In my custom class there is an init method that starts the processing. This method invokes several other methods that handle the majority of the work.
My thinking was that I can use Event Queues something as such:
public class MyWidgetController extends GenericForwardComposer
{
public void init(final Component comp)
{
//other method logic ...
EventQueue queue = EventQueues.lookup("myQueue", EventQueues.SESSION, true);
queue.subscribe(this); //not sure
queue.publish(new Event("onInitPrimaryLoad", componentA, ""));
queue.publish(new Event("onInitSecondaryLoad", componentB, ""));
}
#ViewEvent(componentID = "componentA", eventName = "onInitPrimaryLoad")
public void onInitPrimary( final Event event){ //logic }
#ViewEvent(componentID = "componentB", eventName = "onInitSecondaryLoad")
public void onInitSecondary( final Event event){ //logic }
//other class methods…
}
Not sure if this is all correct. Don't really need a callback method as the Events (publish) themselves are loading the UI components with data. The application runs with no issue but I'm not sure if I'm implementing this correctly.
Any advice or corrections are appreciated
The #ViewEvent seems to be Hybris specific and is not part of the ZK framework, that's why I can't comment on it.
Your example doesn't do async processing at all, the events are published into the current thread and the ui will block and only return after all these events have been processed. (even worse using a SESSION scoped event queue the events are published into all desktops (roughly browser tabs) of that user - most likely executing your heavy work multiple times. You should use a DESKTOP scoped event queue instead.
Also I don't fully understand why you don't need a callback ... when doing async processing you always need some kind of callback or create a thread manually.
Especially in ZK it is vital to perform the heavy work in a separate thread. Once the data is retrieved lock the UI as short as possible to perform updates to the component tree or component models - this keeps the UI as responsive to the user as possible.
The EventQueue usage is described in the official docs.
Based on those I create 2 runnable examples illustrating the simplified and the more generic approach.
As an alternative you can activate/deactivate a ZK desktop directly without using event queues as in this (my preferred) example.

Java MVC Where/When to get my view on EDT and how my controller do actions on EDT?

So im quite new to MVC structure.And im really confused on where/when to add my Gui part on EDT.
This is where im really confused:
public class ECPS_MVC {
//edt?
EcpsView view =new EcpsView();//shoud i put it on edt here?? SwingUtilities... etc
//edt?
EcpsModel model =new EcpsModel();
EcpsController controler=new EcpsController(view,model);
}
I have seen question on how to start gui on edt when using mvc
How to Start a Java MVC Application With a Swing GUI
And answer suprised me.Why shoud be Model on edt as well?Is that really correct??I dont think so.
So question1- When is the best time to put my Gui on edt.When i create View?
question 2- Do i have to do updates from my controller like this?Each time? -
public void setIconLabel(final Icon icon) {
SwingUtilities.invokeLater(new Runnable() {//with swingutil on each method where i work with gui?
#Override
public void run() {
myLabel.setIcon(icon);
}
});
}
If you understand please point me right direction and if needed provide short example code.Thank you.
Anything that interacts or can change the UI in anyway MUST do so from within the context of the Event Dispatching Thread.
Swing, by design, is not thread safe. That is, there are no checks in the default libraries to make determinations about what thread the various models and components are been executed on, it is assumed the developer will already have made these determinations.
So question1- When is the best time to put my Gui on edt.When i create View?
Immediately. You have no way of knowing when a component may become realised (displayed on the screen and/or attached to a native peer)
question 2- Do i have to do updates from my controller like this?Each time? -
No, in fact, I'd be very worried if I found myself coding like this all time. Make the determination that the models and components MUST be executed within the context of the EDT and make whatever is interacting with these models and components meet these requirements.
This would mean, if you are loading data from a separate Thread, you would need to ensure that any time they update the model, they are synchronizing these updates to the EDT to ensure that if the model notifies the UI, it all occurs within the context of the EDT.
Don't make assumptions about the state of the model, statements like "I know..." will come back to haunt you, especially when some one else makes use of your API.
Unless you physically create the model yourself (outside the EDT) and guarantee it's isolation while it's being loaded, don't assume anything that is given to you isn't attached to the UI in some way.
An easier solution is to use a SwingWorker when you want to perform operations off the EDT, as it provides this synchronisation via it's publish/process/done methods

Swing Worker Thread : Inner class vs passing parameter

I know SO is for specific questions but I need an advise on what is the correct practice in Java for working with swing worker thread.
My application generates large HTML text in response to a calculation process which is is displayed in a jTextPane. To avoid blocking the GUI I used to do the calculation in a Swing Worker Thread.
My problem is the following to start the calculation I need plenty information available in different menus checkboxes and listbox of the GUI, and at the end of the calculation I need to start functions within the EDT.
Here are 2 possibilities for me :
First one is to send plenty of information to my Swing Worker and also need to pass the MainFrame to access specific functions in the "done()"
public class MyWorker extends SwingWorker<Void, Void> {
private MyMainFrame frame;
public MyWorker(plenty of params) {
}
#Override
public Void doInBackground() {
//my background process
}
#Override
public void done() {
frame.myfunc1;
frame.myfunc2;
frame.myfunc3;
}
}
Second one would be to use a Inner Class
Which one is correct to do in Java. If both are "correct" what are the pros and cons of one against the other.
Both approaches are OK. The advantage of an inner class is that it has access to the internals of the enclosing object. The disadvantage is that it's not reusable in another context (another frame which would have a similar interface, for example).
Just make sure your code is well structured and readable. For example, you might want to extract the three method calls in your done() method in a single method of the frame.
If it is the large amount of parameters you have to pass in the constructor that is bothering you, you can group those parameters in a container object and just pass the container (e.g. a MyWorkerContext class).
I personally would try to avoid passing the UI (elements) itself, but rather pass a model/stream/... which will be updated by the SwingWorker, allowing me to refactor the UI later on without having to fiddle with my SwingWorker class.

How to synchronize Swing model with a rapidly changing "real" model?

As is widely known, anything related to Swing components must be done on the event dispatch thread. This also applies to the models behind the components, such as TableModel. Easy enough in elementary cases, but things become pretty complicated if the model is a "live view" of something that must run on a separate thread because it's changing quickly. For example, a live view of a stock market on a JTable. Stock markets don't usually happen on the EDT.
So, what is the preferable pattern to (de)couple the Swing model that must be on the EDT, and a "real", thread-safe model that must be updateable from anywhere, anytime? One possible solution would be to actually split the model into two separate copies: the "real" model plus its Swing counterpart, which is is a snapshot of the "real" model. They're then (bidirectionally) synchronized on the EDT every now and then. But this feels like bloat. Is this really the only viable approach, or are there any other, or more standard, ways? Helpful libraries? Anything?
I can recommend the following approach:
Place events that should modify the table on a "pending event" queue, and when an event is placed on the queue and the queue is empty then invoke the Event Dispatch thread to drain the queue of all events and update the table model. This optimisation means you are no longer invoking the event dispatch thread for every event received, which solves the problem of the event dispatch thread not keeping up with the underlying event stream.
Avoid creation of a new Runnable when invoking the event dispatch thread by using a stateless inner class to drain the pending event queue within your table panel implementation.
Optional further optimisation: When draining the pending event queue minimise the number of table update events fired by remembering which table rows need to be repainted and then firing a single event (or one event per row) after processing all events.
Example Code
public class MyStockPanel extends JPanel {
private final BlockingQueue<StockEvent> stockEvents;
// Runnable invoked on event dispatch thread and responsible for applying any
// pending events to the table model.
private final Runnable processEventsRunnable = new Runnable() {
public void run() {
StockEvent evt;
while ((evt = stockEvents.poll() != null) {
// Update table model and fire table event.
// Could optimise here by firing a single table changed event
// when the queue is empty if processing a large #events.
}
}
}
// Called by thread other than event dispatch thread. Adds event to
// "pending" queue ready to be processed.
public void addStockEvent(StockEvent evt) {
stockEvents.add(evt);
// Optimisation 1: Only invoke EDT if the queue was previously empty before
// adding this event. If the size is 0 at this point then the EDT must have
// already been active and removed the event from the queue, and if the size
// is > 0 we know that the EDT must have already been invoked in a previous
// method call but not yet drained the queue (i.e. so no need to invoke it
// again).
if (stockEvents.size() == 1) {
// Optimisation 2: Do not create a new Runnable each time but use a stateless
// inner class to drain the queue and update the table model.
SwingUtilities.invokeLater(processEventsRunnable);
}
}
}
As far as I understand, you don't want to implement Swing model interfaces in your real model, do you? Can you implement a Swing model as a "view" over a part of a real model? It will translate its read-access getValueAt() to the calls of the real model, and the real model will notify Swing model about the changes , either providing a list of changes or assuming that Swing model will take care of quering the new values of everything it currently is showing.
The usual approach is to send "signals" of some kind to which the UI listens. In my code, I often use a central dispatcher which sends signals that contain the object that was modified, the name of the field/property plus the old and new value. No signal is sent for the case oldValue.equals(newValue) or oldValue.compareTo(newValue) == 0 (the latter for dates and BigDecimal).
The UI thread then registers a listener for all signals. It then examines the object and the name and then translates that to a change in the UI which is executed via asyncExec().
You could turn that into a listener per object and have each UI element register itself to the model. But I've found that this just spreads the code all over the place. When I have a huge set of objects on both sides, I sometimes just use several signals (or events) to make things more manageable.

Categories

Resources