繁体   English   中英

在需要很长时间的函数之前和之后显示来自ActionListener的消息

[英]Displaying a message from an ActionListener before and after a function that takes a long time

我有一个方法可能需要很长时间才能执行。 我们称之为longTime();

从按钮上的动作侦听器调用此方法。

我想在执行此方法时显示"Please wait.."消息。

问题是Jframe没有响应,似乎卡住或等待某事。

重要说明: longTime()的运行时间可能不同。 只有超过2-3秒才会出现问题。

我试图在invokeLate做所有这些,但这没有帮助。

SwingUtilities.invokeLater(new Runnable() {
  @Override
  public void run() {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    JLabel label = new JLabel("Please wait...");
    label.setFont(new Font("Serif", Font.PLAIN, 25));
    frame.getContentPane().add(label, BorderLayout.CENTER);
    frame.setLocationRelativeTo(null);
    frame.setUndecorated(true);
    frame.pack();
    frame.setAlwaysOnTop(true);
    frame.setVisible(true);
    try{            
      longTime();  //HERE IS THE FUNCTION THAT TAKES A LONG TIME  
    }catch(Exception e){   }
    frame.dispose();  //AFTER THE LONG FUNCTION FINISHES, DISPOSE JFRAME        
  } 
});

有关如何解决此问题的任何想法?

所有冗长的任务都应该在一个单独的线程中进行,以防止GUI线程( Event Dispatch Thread )被阻塞。 我建议您考虑使用SwingWorker对象来执行冗长的任务并在完成时执行操作。

您可以在http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html上阅读有关此主题的更多信息。

  • 有两种方法,通过使用基于JXLayer (Java6)Glasspane JLayer (Java7) ,使用JLabel (带有intermediate Icon )调用

    1. 来自SwingWorker

    2. (最简单)来自Runnable.Thread (输出到Swing GUI必须包装在invokeLater

  • 仔细考虑Swing中的Concurency ,所有更改都必须在EDT上完成

  • 不要重新发明轮子,代码示例由@camickr

通过一个简单的例子突出显示mKorbel和Ducan的推荐(两者都是+1)......

public class RunLongTime {

    public static void main(String[] args) {
        new RunLongTime();
    }

    public RunLongTime() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface WorkMonitor {

        public void updateProgress(float progress);
        public void done();

    }

    public class TestPane extends JPanel implements WorkMonitor {

        private JLabel message;
        private JButton button;

        public TestPane() {
            message = new JLabel("Click to get started");
            button = new JButton("Start");
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.insets = new Insets(2, 2, 2, 2);
            add(message, gbc);
            add(button, gbc);

            button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    button.setEnabled(false);
                    message.setText("Getting started...");
                    BackgroundWorker worker = new BackgroundWorker(TestPane.this);
                    worker.execute();
                }
            });
        }

        @Override
        public void updateProgress(float progress) {
            message.setText("Please wait..." + NumberFormat.getPercentInstance().format(progress));
        }

        @Override
        public void done() {
            message.setText("All done...");
            button.setEnabled(true);
        }

    }

    public class BackgroundWorker extends SwingWorker<Void, Float> {

        private WorkMonitor monitor;

        public BackgroundWorker(WorkMonitor monitor) {
            this.monitor = monitor;
        }

        @Override
        protected void done() {
            monitor.done();
        }

        @Override
        protected void process(List<Float> chunks) {
            monitor.updateProgress(chunks.get(chunks.size() - 1));
        }

        @Override
        protected Void doInBackground() throws Exception {
            for (int index = 0; index < 1000; index++) {
                Thread.sleep(125);
                publish((float)index / 1000f);
            }
            return null;
        }

    }

}

您必须生成另一个线程并在另一个线程中运行longTime()任务。 调用invokeLater()仍然在UI线程中运行它,您不想阻止它。

考虑以下代码:

    final JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    JLabel label = new JLabel("Please wait...");
    label.setFont(new Font("Serif", Font.PLAIN, 25));
    frame.getContentPane().add(label, BorderLayout.CENTER);
    frame.setLocationRelativeTo(null);
    frame.setUndecorated(true);
    frame.pack();
    frame.setAlwaysOnTop(true);
    frame.setVisible(true);

    new Thread(new Runnable() {
        @Override
        public void run() {
        try{            
            longTime();  //HERE IS THE FUNCTION THAT TAKES A LONG TIME  
        }catch(Exception e){   }
            frame.dispose();     //AFTER THE LONG FUNCTION FINISHES, DISPOSE JFRAME     
        } 
        }).start();

您可能希望从新生成的线程更新数据模型。 那将是使用SwingUtilities.invokeLater()的正确位置。 不要在这个新线程中更新模型。 UI组件的模型必须仅在UI线程中更新。 稍后调用就是这样做的。

只需在新线程中调用longTime() ,例如

new Thread(){ public void run() {longTime();}}.start();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM