【问题标题】:Showing text in JTextArea while calculating计算时在 JTextArea 中显示文本
【发布时间】:2011-05-22 18:26:49
【问题描述】:

我正在编写的一个应用程序包括一个 JButton 和一个 JTextArea。单击按钮会导致长时间计算,从而导致 JTextArea 中显示文本。即使计算很长,我也可以在旅途中得到中间结果(例如,考虑一个将 pi 近似为 100 位的应用程序 - 每隔几秒我就可以写另一个数字)。问题是,即使我编写(在 ActionListener 类中,因为按钮调用了计算)将 JTextArea 的文本设置为某些东西,计算完成时它也不会显示,我只能看到结尾结果,计算结束后。

为什么会这样,我该如何解决?

提前谢谢你。

【问题讨论】:

    标签: java swing concurrency background jtextarea


    【解决方案1】:

    您的问题是您在主 Swing 线程 EDT 中进行了长时间的计算,这将冻结您的整个 GUI,直到该过程自行完成。一种解决方案是使用后台线程进行计算,并且一种简单的方法是使用 SwingWorker 为主 Swing 线程、EDT 创建线程背景,并将中间结果发布/处理到 JTextArea 中。有关 SwingWorkers 和 EDT 的更多信息,请查看此处:Concurrency in Swing

    另外,如果您提供一个体面的sscce,我们可能会为您提供更详细的回复,甚至可能提供示例代码。

    SSCCE 示例:

    import java.awt.event.*;
    import java.text.DecimalFormat;
    import java.util.List;
    import javax.swing.*;
    
    public class InterimCalc {
       private JPanel mainPanel = new JPanel();
       private JTextField resultField = new JTextField(10);
       private JButton doItBtn = new JButton("Do It!");
       private DecimalFormat dblFormat = new DecimalFormat("0.0000000000");
       private SwingWorker<Void, Double> mySwingWorker = null;
    
       public InterimCalc() {
          mainPanel.add(doItBtn);
          mainPanel.add(resultField);
          displayResult(0.0);
    
          doItBtn.addActionListener(new DoItListener());
       }
    
       public void displayResult(double result) {
          resultField.setText(dblFormat.format(result));
       }
    
       public JPanel getMainPanel() {
          return mainPanel;
       }
    
       private class DoItListener implements ActionListener {
    
          public void actionPerformed(ActionEvent e) {
             if (mySwingWorker != null && !mySwingWorker.isDone()) {
                mySwingWorker.cancel(true);
             }
             displayResult(0.0);
             mySwingWorker = new MySwingWorker();
             mySwingWorker.execute();
          }
       }
    
       private class MySwingWorker extends SwingWorker<Void, Double> {
    
          private static final int INTERIM_LENGTH = 10000; // how many loops to do before displaying
    
          @Override
          protected Void doInBackground() throws Exception {
             boolean keepGoing = true;
             long index = 1L;
             double value = 0.0;
             while (keepGoing) {
                for (int i = 0; i < INTERIM_LENGTH; i++) {
                   int multiplier = (index % 2 == 0) ? -1 : 1;
                   value += (double)multiplier / (index);
                   index++;
                }
                publish(value);
             }
             return null;
          }
    
          @Override
          protected void process(List<Double> chunks) {
             for (Double dbl : chunks) {
                displayResult(dbl);
             }
          }
    
       }
    
       private static void createAndShowUI() {
          JFrame frame = new JFrame("Decay Const");
          frame.getContentPane().add(new InterimCalc().getMainPanel());
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          java.awt.EventQueue.invokeLater(new Runnable() {
             public void run() {
                createAndShowUI();
             }
          });
       }
    }
    

    【讨论】:

    • 感谢您的回答。恐怕我不太了解你在说什么。我的代码大致是这样的:String s = inputArea.getText(),然后我想打印一个字符串列表,比如第一个是 s,下一个是 f(s),当 f 是获取和返回一个字符串(运行 f 大约需要两秒钟),第二个是 f(f(s)) 等等。我希望它向我展示这个过程,也就是说,一秒钟后我会在 JTextArea 中看到 s > f(s),再过一两秒我会看到 s > f(s) > f(f(s) )) 等等。
    • 不能调用某个方法解冻一次GUI吗?
    • @ronash - 他只是解释了你为什么会被冻结。请在继续之前阅读他给你的链接,这样你就会明白答案。
    • @ronash:不,您不能“解冻”一次 GUI。相反,您需要对其进行设计以使其不会冻结,而后台线程是解决此问题的方法。 SwingWorker 不是绝对必要的,但它确实简化了流程。我稍后会在上面发布一个小例子......
    • 非常非常感谢(两位)!! :-)
    【解决方案2】:

    您可能还想显示某种旋转的 gif 或“进度条”来表明正在计算答案;对用户的反馈很好。

    (一旦你使用了一个 swingworker,那么 gui 就不会冻结,并且 gui 可以在计算发生时做自己的事情)

    【讨论】:

      猜你喜欢
      • 2017-09-03
      • 2019-02-05
      • 2012-05-27
      • 1970-01-01
      • 1970-01-01
      • 2014-11-16
      • 2011-09-15
      • 2018-11-14
      • 1970-01-01
      相关资源
      最近更新 更多