Swing, Passive View and Long running tasks

I am trying to implement a Passive View based on a gui system. Basically, I want my view implementation (the part that actually contains the swing code) to be minimal and do most of the work in my Presenter class. The presenter should not have anything to do with the swing, and should also "start the show", that is, tell what to do, and not vice versa.

I encounter problems when working with tasks with a large number of tasks and thread separation in general. I want the GUI updates to run on EDT, and the presenter logic to another thread. If I want the host to update the GUI part, it's pretty easy, I write something like this:

public interface View { void setText(String text); } public class Presenter { View view; ... public void setTextInVIew() { view.setText("abc"); } } public class MyFrame implements View { JTextField textField; ... public void setText(final String text) { SwingUtilities.InvokeLater(new Runnable() { public void run() { textField.setText(text); } }); } } 

However, when the GUI needs to inform the host that some action has occurred, I want to disable EDT in response to it in another thread:

 public class Presenter { ... public void buttonPressed() { // shouldn't run on EDT } } public class MyFrame implements View { JButton button; public MyFrame() { ... button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { presenter.ButtonPressed(); } }); } } 

since actionPerformed code is run from EDT, so will Presenter.buttonPressed. I know that swing has the SwingWorker concept of launching tasks in another thread, however it looks like I have to insert the swing code into my host and the view starts the show. Any ideas how to solve this?

+4
source share
4 answers

you can do something like the following that will hold your GUI code in place and just do the work to exit the EDT:

  button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { SwingWorker sw = new SwingWorker() { public Object doInBackground(){ presenter.ButtonPressed(); return null; } }; sw.execute(); } }); 
+2
source

You might be interested in the Task API to avoid all patterns. Otherwise, the akf solution looks great (although there is no need to create a variable for SwingWorker, you can just add a new one and execute anonymous).

+2
source

Another approach to the SwingWorker solution set forth by others is the use of a thread-bound event bus. I really think this might be the best option for the type of denouement you're going to.

Departure: EventBus

There are other implementations of bus architecture, but EventBus is popular.

- update -

So, EventBus will provide a very clean way to proxy from non-EDT to EDT (much better than tons of explicit calls to SwingUtilities.invokeLater ()), but basically does the same thing. Although EventBus is able to bundle many notifications and delete them into a single executable EDT, so performance will be better).

But this does not apply to the need for proxy events from EDT and launches them in a worker thread. The EventBus has a ThreadSafeEventService class that can probably be used as the basis for such a beast - it can be associated with an ExecutorService, for example, to handle specific event logs for specific listeners.

I think the key to all of this for me is that in any solution you come up with, it should try to encapsulate EDT on / off

BTW - What you're asking is really like the Microsoft Thread Threading model.

0
source

OK. I have one more option for you: Spin

Ultimately, all of these solutions are proxy calls between threads. I believe the goal is to find a solution that does not require ready-made code templates at your end. For example, you can connect all your listeners to check if they are in the corresponding workflow, and then to the proxy server in the ExecutorService, if not. But this is a big problem. It’s much better to get proxying going on in the layer between your business and presentation objects β€” the binding / listener / what you want to call the layer.

0
source

Source: https://habr.com/ru/post/1302481/


All Articles