0

我有将系统输出重定向到 jtext 区域的代码,但是 jtextarea 直到代码完成运行后才会更新。如何修改代码以使 jtextarea 在运行时实时更新?

private void updateTextArea(final String text) {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            consoleTextAreaInner.append(text);
          }
        });
      }
private void redirectSystemStreams() {
      OutputStream out = new OutputStream() {
        @Override
        public void write(int b) throws IOException {
          updateTextArea(String.valueOf((char) b));
        }

        @Override
        public void write(byte[] b, int off, int len) throws IOException {
          updateTextArea(new String(b, off, len));
        }

        @Override
        public void write(byte[] b) throws IOException {
          write(b, 0, b.length);
        }
      };

      System.setOut(new PrintStream(out, true));
      System.setErr(new PrintStream(out, true));
    }    

其余代码主要只是一个按钮的动作监听器:

private void updateButtonActionPerformed(java.awt.event.ActionEvent evt) {                                             
    // TODO add your handling code here:
    String shopRoot = this.shopRootDirTxtField.getText();
    String updZipPath = this.updateZipTextField.getText();
    this.mainUpdater = new ShopUpdater(new File(shopRoot), updZipPath);
    this.mainUpdater.update();
}

该 update() 方法开始在文件系统上复制+粘贴文件的过程,并在该过程中使用 system.out.println 提供有关程序当前位置的最新状态,以参考还有多少文件它必须复制。

4

2 回答 2

3

很难 100% 肯定地判断出了什么问题,因为我们没有看到很多涉及到的关键代码,但很有可能您遇到了 Swing 线程问题。您需要在后台线程中读取流,然后在 Swing 事件线程(EDT)上调用对文本区域的更新方法。否则,您将在等待流读取时占用 EDT,从而完全冻结您的 GUI。SwingWorker 可以很好地工作。考虑在每次遇到新行时发布到 JTextArea。

例如:

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

public class MyRedirectStream {

   private JTextArea textArea;

   public MyRedirectStream(JTextArea gui) {
      this.textArea = gui;
   }

   public void redirect() {
      System.setOut(new PrintStream(new MyOutStream(), true));
      System.setErr(new PrintStream(new MyOutStream(), true));      
   }

   private class MyOutStream extends OutputStream {
      private static final int MAX_LENGTH = 1600;
      private StringBuilder sb = new StringBuilder(MAX_LENGTH + 100);

      @Override
      public void write(int b) throws IOException {
         sb.append((char)b);
         if (sb.length() > MAX_LENGTH) {
            sendToTextArea(sb.toString());
            sb = new StringBuilder();
         }
      }

      @Override
      public void flush() throws IOException {
         sendToTextArea(sb.toString());
         sb = new StringBuilder();
         super.flush();
      }
      private void sendToTextArea(final String text) {
         SwingUtilities.invokeLater(new Runnable() {
            public void run() {
               textArea.append(text);
            }
         });
      }

   }   
}

和:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class StreamToTextArea2 {
   public static void main(String[] args) {
      final TextPanel gui = new TextPanel();
      final MyRedirectStream myRedirectStream = new MyRedirectStream(
            gui.getTextarea());
      myRedirectStream.redirect();

      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            final JFrame frame = new JFrame("Redirect");
            JButton showTextBtn = new JButton(new AbstractAction("Show Text") {

               @Override
               public void actionPerformed(ActionEvent arg0) {
                  JFileChooser fileChooser = new JFileChooser();
                  int result = fileChooser.showOpenDialog(frame);
                  if (result == JFileChooser.APPROVE_OPTION) {
                     gui.clearText();
                     final File file = fileChooser.getSelectedFile();
                     new Thread(new Runnable() {
                        public void run() {
                           try {
                              Scanner scan = new Scanner(file);
                              while (scan.hasNextLine()) {
                                 System.out.println(scan.nextLine());
                              }
                           } catch (FileNotFoundException e) {
                              e.printStackTrace();
                           }

                        }
                     }).start();
                  }
               }
            });
            JButton clearTextBtn = new JButton(
                  new AbstractAction("Clear Text") {

                     @Override
                     public void actionPerformed(ActionEvent e) {
                        gui.clearText();
                     }
                  });
            JPanel btnPanel = new JPanel();
            btnPanel.add(clearTextBtn);
            btnPanel.add(showTextBtn);

            frame.getContentPane().add(gui);
            frame.getContentPane().add(btnPanel, BorderLayout.SOUTH);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);

         }
      });

   }
}

import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

class TextPanel extends JPanel {
   private JTextArea textarea = new JTextArea(20, 40);

   public TextPanel() {
      setLayout(new BorderLayout());
      JScrollPane scrollPane = new JScrollPane(textarea);
      scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
      add(scrollPane);
   }

   public JTextArea getTextarea() {
      return textarea;
   }

   public void clearText() {
      textarea.setText("");
   }

}
于 2013-10-31T21:19:07.183 回答
1

您确实编写了 invokeLater,它稍后会调用它。迟到多少是不确定的,除非您执行一些主动的操作以使其确定。例如,您可以在文件之间插入 Thread.sleep 调用。

于 2013-10-31T21:49:48.830 回答