Streaming implementation in Swing EDT?

My project is built on Java Swing. It generates an EDT that displays my GUI (which works correctly).

Entering the program that initializes 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 frame / etc is clicked in my GUI, the Controller class should take action on the model.

My questions are:

  • Should I override the controller code in the new SwingWorker?
    • If not, should I wrap my model code in a new SwingWorker?
  • If I migrate controller code to threads, do I need to keep the shared state variables in sync in my model?
  • If my model, running on a new thread, notifies my GUI of changes, will this happen in 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?
    }
}

      

+3


source to share


3 answers


Instead of updating your model from doInBackground()

, publish()

interim results, and updating your model from process()

, which runs on EDT. This example JTable

matches yours View

and TableModel

matches yours Model

. Note that it is JTable

listening on its own TableModel

.



+4


source


You can read about it here: Improving Application Performance with SwingWorker in Java SE 6 . In short: all time consuming operations that do not affect the user interface must be performed on a different thread . To show the results of the work, you must return to EDT. For example, if you are searching a database, you should show a progress bar (usually infinite) and start searching with SwingWorker. You must be in EDT to show search results in a table. Alternatively you can use the foxtrot lib(this allows you to make your code more Swing friendly without redesigning it). If your controller code is constantly updating swing widgets, you should execute it in EDT, or at least perform those UI updates in EDT (using SwingUtilities.invokeLater, chunk handling in SwingWorker, or swing.Timer). So your sample is wrong: the model update needs to be updated in the EDT.



+4


source


One alternative approach, starting with Java Concurrency in Practice 9.4.2, uses the "Split" or "Shared Data Model". You update your business model on whatever thread you want, probably on a lengthy non-EDT thread. But instead of directly calling notifyListeners () and worrying about which thread you are on, just call myComponent.repaint (), which will queue up a redraw request on the EDT.

Then, somewhere in your method paintComponent()

, you explicitly grab all the new data from the Model, usually in the methodmodelToView()

   commentTextArea.setText(myModel.getCommentText());
   fooLabel.setText(myModel.getFooText());
   ...

      

Surfaces are what flows are not a problem, and at least in some mind, it "makes sense" and the model is nicely separated from the view. The downside is that you reset all values ​​every time. So if you have 100 JComponents then 100 things will be installed. Also, the view is quite closely related to the model.


Working code examples

@MadProgrammer and @kleopatra are correct that if the view itself contains components that are updated, you get an "infinite doom loop". For proof, see

Demo_14716901_Fails

However, if the view is isolated from the components, you avoid an infinite loop. Typically, a higher level view will contain things like JSplitPanes, JScrollPanes placement, holding boxes or more JPanels, storing actual low level components. Therefore, this requirement, IMO, is not unreasonable.

Working Code Demo_14716901_Works

Some comments added for Downvoters :

Some people want to beat Swing. They write control code or control algorithms and just want to get their work done without worrying about EDT, endless SwingWorkers and invokeLaters. This method allows them to do their job. With one important caveat, this works. (Personally, I understand and generally love Swing, but many don't.)

While Swing components are beautifully MVC, they tend to be too high level. The "real" model is not one line, it is tens of values. The "real" view is not one JLabel, many JPanels, each with many components, combined with scrollers, splitters, etc. This method is usually better suited to the real world, allowing the programmer to think naturally at a higher level.

For "bad practice," take it with Brian Goetz, Josh Bloch, etc. ok, this is a "call to power", but it works for me. :-)

-2


source







All Articles