My GUI is frozen

后端 未结 6 1734
青春惊慌失措
青春惊慌失措 2020-12-11 13:45

I have something I can\'t understand: my Swing GUI contains a \'play\' and \'pause\' button. I have also a static variable that defines \'ON\' and \'OFF\' states. (The main

6条回答
  •  执笔经年
    2020-12-11 14:03

    The event dispatch thread (EDT) is the only thread in which it's safe to read or update the GUI.

    The pause button should be setting the on/off variable in the event dispatch thread.

    The time-consuming operation, and the loop, should not be in the EDT. (The loop should also not be running continuously doing nothing but check the variable, or it can easily eat all your CPU. If it has nothing else to do it should check, and then call Thread.sleep() for some length of time (say 100ms).)

    If you can prove that the on/off variable is being set to OFF, but that nonetheless it's always read as ON, it may be that the variable's value is not being copied from the EDT to the worker thread. Make it volatile, or synchronize access to it, or use an AtomicReference, or read it in the EDT using SwingUtilities.invokeAndWait().

    SwingWorker probably is the simplest way to go, here. Implement your time-consuming operation, and the on/off check, in the doInBackground() method, and your GUI update in the done() method.

    public enum State {
        RUNNING, STOPPED
    }
    
    public class ThreadSafeStateModel {
        private State state = State.STOPPED;
    
        public synchronized void stop() {
            state = State.STOPPED;
        }
    
        public synchronized void start() {
            state = State.RUNNING;
        }
    
        public boolean isRunning() {
            return state == State.RUNNING;
        }
    }
    
    public class ExpensiveProcessWorker extends SwingWorker {
    
        private final ThreadSafeStateModel model;
    
        public ExpensiveProcessWorker(ThreadSafeStateModel model) {
            this.model = model;
        }
    
        @Override // Runs in background
        protected Void doInBackground() throws Exception { 
            while (model.isRunning()) {
                // do one iteration of something expensive
            }
            return null;
        }
    
        @Override // Runs in event dispatch thread
        protected void done() { 
            // Update the GUI
        }
    }
    
    public class StopButton extends JButton {
        public StopButton(final ThreadSafeStateModel model) {
            super(new AbstractAction("Stop") {
                @Override
                public void actionPerformed(ActionEvent e) {
                    model.stop();
                }
            });
        }
    }
    
    public class StartButton extends JButton {
        public StartButton(final ThreadSafeStateModel model) {
            super(new AbstractAction("Start") {
                @Override
                public void actionPerformed(ActionEvent e) {
                    model.start();
                    new ExpensiveProcessWorker(model).execute();
                }
            });
        }
    }
    

    (A lot could be done to clean this up depending on the real application, but you get the idea.)

提交回复
热议问题