有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在程序运行时保持JPanel中的计时器处于活动状态

我在一个叫做MainFrame的类中创建了一个GUI。GUI的一个JPanel以秒为单位显示当前时间和日期。当用户决定使用GUI分析数据时,它会调用一个处理数据的类。当数据处理发生时,计时器暂停,然后在数据处理结束时恢复。即使程序正在运行,如何让计时器持续运行?计时器是它自己的线程,但我不知道从哪里开始JPanel的线程。 下面是一些代码裁剪

应用程序。java(启动整个GUI的应用程序)

public class App {

    public static void main(String[] args) {

        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                new MainFrame();
            }
        });
    }

}

大型机(处理JPanel和dataprocess impl的类)

public class MainFrame extends JFrame {

    private DataProcess dataProcess = null;
...
...
    private StatusPanel statusPanel;
...
...
public MainFrame() {
...
        setJMenuBar(createFrameMenu());

        initializeVariables();
        constructLayout();
        createFileChooser();
        constructAppWindow();
}

    private void initializeVariables() {

        this.dataProcess = new DataProcess();
...
        this.statusPanel = new StatusPanel();
...
}
    private void constructLayout() {
        JPanel layoutPanel = new JPanel();
        layoutPanel.setLayout(new GridLayout(0, 3));
        layoutPanel.add(dataControlsPanel());

        setLayout(new BorderLayout());
        add(layoutPanel, BorderLayout.CENTER);
        add(statusPanel, BorderLayout.PAGE_END);
    }

状态面板(显示计时器等的面板)

public class StatusPanel extends JPanel {

    private static final long serialVersionUID = 1L;
    private JLabel statusLabel;
    private JLabel timeLabel;

    private Timer timer;

    public StatusPanel() {
        initializeVariables();
        constructLayout();
        startTimer();
    }

    private void constructLayout() {
        setLayout(new FlowLayout(FlowLayout.CENTER));
        add(statusLabel);// , FlowLayout.CENTER
        add(timeLabel);
    }

    public void startTimer() {
        this.timer.start();
    }

    public void stopTimer() {
        this.timer.setRunning(false);
    }

    private void initializeVariables() {
        this.statusLabel = new JLabel();
        this.timeLabel = new JLabel();
        this.statusLabel.setText(StringConstants.STATUS_PANEL_TEXT);
        this.timer = new Timer(timeLabel);
    }

}

计时器。java(StatusPanel中使用的计时器)

public class Timer extends Thread {

    private boolean isRunning;
    private JLabel timeLabel;
    private SimpleDateFormat timeFormat;

    public Timer(JLabel timeLabel) {
        initializeVariables(timeLabel);
    }

    private void initializeVariables(JLabel timeLabel) {
        this.timeLabel = timeLabel;
        this.timeFormat = new SimpleDateFormat("HH:mm:ss  dd-MM-yyyy");
        this.isRunning = true;
    }

    @Override
    public void run() {
        while (isRunning) {
            Calendar calendar = Calendar.getInstance();
            Date currentTime = calendar.getTime();
            timeLabel.setText(timeFormat.format(currentTime));

            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void setRunning(boolean isRunning) {
        this.isRunning = isRunning;
    }

}

数据处理是通过使用actionlisteners在dataControlsPanel中完成的


共 (1) 个答案

  1. # 1 楼答案

    When the user decides to use the GUI to analyze data, it invokes a class that processes data. When the data process is happening, the timer pauses, then resumes when the dataprocess is over. How can I have the timer continuously run even if the program is running

    首先,你的计时器应该是javax.swing.Timer或“Swing”计时器。这是专门针对Swing事件线程构建的,因此应该避免当前代码显示的许多Swing线程问题,例如:timeLabel.setText(timeFormat.format(currentTime));这会从后台线程发出Swing调用,这是危险的代码。下一个 处理代码应该进入SwingWorker。当worker执行时,可以通过调用计时器上的stop()暂停Swing计时器,或者简单地让计时器继续运行。当SwingWorker完成了它的操作(我通常会在SwingWorker中添加一个PropertyChangeListener来监听),监听它的state属性是否更改为SwingWorker.StateValue.DONE,调用get()来提取它所持有的任何数据,更重要的是捕获可能抛出的任何异常

    例如:

    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.TimeUnit;
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class MyApp extends JPanel {
        // display the date/time
        private static final String DATE_FORMAT = "HH:mm:ss  dd-MM-yyyy";
        private static final DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
    
        // timer updates measures seconds, but updates every 0.2 sec's to be sure
        private static final int TIMER_DELAY = 200;
    
        // JLabel that shows the date/time
        private JLabel timeLabel = new JLabel("", SwingConstants.CENTER);
    
        // JButton's Action / listener. This starts long-running data processing
        private Action dataProcessAction = new DataProcessAction("Process Data");
    
        // the SwingWorker that the above Action executes:
        private LongRunningSwProcess longRunningProcess;
    
        // label to display the count coming from the process above
        private JLabel countLabel = new JLabel("00");
    
        public MyApp() {
            // create a simple GUI
            JPanel dataProcessingPanel = new JPanel();
            dataProcessingPanel.add(new JButton(dataProcessAction)); // button that starts process
            dataProcessingPanel.add(new JLabel("Count:"));
            dataProcessingPanel.add(countLabel);        
    
            setLayout(new BorderLayout());
            add(timeLabel, BorderLayout.PAGE_START);
            add(dataProcessingPanel);
            showTimeLabelCurrentTime();
            // create and start Swing Timer
            new Timer(TIMER_DELAY, new TimerListener()).start(); 
        }
    
        // display count from swing worker
        public void setCount(int newValue) {
            countLabel.setText(String.format("%02d", newValue));
        }
    
        // clean up code after SwingWorker finishes
        public void longRunningProcessDone() {
            // re-enable JButton's action
            dataProcessAction.setEnabled(true);
            if (longRunningProcess != null) {
                try {
                    // handle any exceptions that might get thrown from the SW
                    longRunningProcess.get();
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
    
        // display the current time in our timeLabel JLabel
        private void showTimeLabelCurrentTime() {
            long currentTime = System.currentTimeMillis();
            Date date = new Date(currentTime);
            timeLabel.setText(dateFormat.format(date));
        }
    
        // Timer's ActionListener is simple   display the current time in the timeLabel
        private class TimerListener implements ActionListener {
            @Override
            public void actionPerformed(ActionEvent e) {
                showTimeLabelCurrentTime();
            }
        }
    
        // JButton's action. This starts the long-running SwingWorker
        private class DataProcessAction extends AbstractAction {
    
            public DataProcessAction(String name) {
                super(name);
                int mnemonic = (int) name.charAt(0);
                putValue(MNEMONIC_KEY, mnemonic);
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                setEnabled(false); // first disable the button's action
                countLabel.setText("00"); // reset count label
    
                // then create SwingWorker and listen to its changes
                longRunningProcess = new LongRunningSwProcess();
                longRunningProcess.addPropertyChangeListener(new DataProcessListener());
    
                // execute the swingworker
                longRunningProcess.execute();
            }
        }
    
        // listen for state changes in our SwingWorker
        private class DataProcessListener implements PropertyChangeListener {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getPropertyName().equals(LongRunningSwProcess.COUNT)) {
                    setCount((int)evt.getNewValue());
                } else if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
                    longRunningProcessDone();
                }
            }
        }
    
        private static void createAndShowGui() {
            JFrame frame = new JFrame("My App");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(new MyApp());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    }
    

    // mock up of SwingWorker for long-running action
    class LongRunningSwProcess extends SwingWorker<Void, Integer> {
        public static final String COUNT = "count";
        private static final int MIN_TIME_OUT = 5;
        private static final int MAX_TIME_OUT = 10;
        private int count = 0;
    
        @Override
        protected Void doInBackground() throws Exception {
            // all this mock up does is increment a count field 
            // every second until timeOut reached
            int timeOut = MIN_TIME_OUT + (int) (Math.random() * (MAX_TIME_OUT - MIN_TIME_OUT));
            for (int i = 0; i < timeOut; i++) {
                setCount(i);
                TimeUnit.SECONDS.sleep(1);
            }
            return null;
        }
    
        // make count a "bounded" property   one that will notify listeners if changed
        public void setCount(int count) {
            int oldValue = this.count;
            int newValue = count;
            this.count = newValue;
            firePropertyChange(COUNT, oldValue, newValue);
        }
    
        public int getCount() {
            return count;
        }
    }