Java redirected system output to jtext area, doesnt update until calculation is finished

六眼飞鱼酱① 提交于 2019-12-25 06:30:01

问题


I have code that redirects system output to a jtext area, but that jtextarea doesnt update until the code is finished running. How do I modify the code to make the jtextarea update in real time during runtime?

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));
    }    

The rest of the code is mainly just an actionlistener for a button:

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();
}

That update() method begins the process of copying+pasting files on the file system and during that process uses system.out.println to provide an up-to-date status on where the program is currently at in reference to how many more files it has to copy.


回答1:


It's hard to tell with 100% assuredly what is going wrong, as there's a lot of critical involved code that we're not seeing, but there's a good chance that you're running into a Swing threading issue. You need to read the stream in a background thread and then call your update to text area method on the Swing event thread, the EDT. Otherwise you'll tie up the EDT while waiting for the stream to read, completely freezing your GUI. A SwingWorker would work well. Consider publishing to the JTextArea each time a new line is encountered.

For example:

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);
            }
         });
      }

   }   
}

and:

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("");
   }

}



回答2:


You did write invokeLater, and it does invoke it later. How much late is later is indeterminate unless you perform something active to make it determinate. You could, for example, insert Thread.sleep calls between files.



来源:https://stackoverflow.com/questions/19716664/java-redirected-system-output-to-jtext-area-doesnt-update-until-calculation-is

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!