繁体   English   中英

如何实时读写进程并在 JTextArea 中实时显示输出? (Java 摆动)

[英]How can I read and write a process in real time and display output in JTextArea in real time? (Java Swing)

我复制并修改了此处发布的答案代码: Print Output of Process to JTextArea over client server Network in java

我的代码的问题是它只在代码启动时工作一次。 任何对 write 的后续调用都不会执行任何操作。

这是我的代码:

MainFrame 类

public class MainFrame extends JFrame {

    private JTextArea Output;
    private JScrollPane outputScrollPane;
    private JButton clickMe;

    private ProcessThread processThread;
    private ExecutorService execService;

    public MainFrame() {
        setTitle("StackOverflow");
        setSize(700, 850);
        setMinimumSize(new Dimension(650,800));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        Output = new JTextArea();
        Output.setEditable(false);
        outputScrollPane = new JScrollPane(Output);
        outputScrollPane.setPreferredSize(new Dimension(100, 150));
        outputScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        add(outputScrollPane, BorderLayout.CENTER);

        clickMe = new JButton("click Me");
        add(clickMe, BorderLayout.SOUTH);

        execService = Executors.newSingleThreadExecutor();
        processThread = new ProcessThread(Output);
        execService.submit(processThread);

        clickMe.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        processThread.write("some command\n"); //does nothing (doesn't update JTextArea with the process' response)
                    }
                });
            }
        });

        setVisible(true);
    }
}

进程线程类:

public class ProcessThread implements Runnable {

     private JTextArea ta;

     private WriteWorker writeWorker;
     private ReadWorker readWorker;
     private CountDownLatch shutDownLatch;

     public ProcessThread(JTextArea ta) {
            this.ta = ta;
        }

     public void write(String text) {
            if (writeWorker != null) {
                if (writeWorker.getState() == SwingWorker.StateValue.STARTED) {
                    writeWorker.write(text);
                } else {
                    throw new IllegalStateException("Write worker is not running");
                }
            } else {
                throw new NullPointerException("Write worker is null");
            }
        }

     public void close() {
            if (writeWorker != null) {
                writeWorker.cancel(true);
            }
            if (readWorker != null) {
                readWorker.cancel(true);
            }

            // Force the CountDownLatch to release
            if (shutDownLatch != null) {
                shutDownLatch.countDown();
                shutDownLatch.countDown();
            }
        }

    @Override
    public void run() {
        try {
            Process myProcess;
            myProcess = new ProcessBuilder("C:\\Folder\\executable.exe").start();
            InputStream processInputStream = myProcess.getInputStream();
            OutputStream processOutputStream = myProcess.getOutputStream();

            writeWorker = new WriteWorker(processOutputStream);
            readWorker = new ReadWorker(processInputStream, ta);

            writeWorker.addPropertyChangeListener(new PropertyChangeHandler());
            readWorker.addPropertyChangeListener(new PropertyChangeHandler());

            writeWorker.execute();
            readWorker.execute();

            shutDownLatch = new CountDownLatch(2);
            shutDownLatch.await();
        } catch (IOException | InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    protected class PropertyChangeHandler implements PropertyChangeListener {

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            SwingWorker worker = (SwingWorker) evt.getSource();
            if (worker.getState() == SwingWorker.StateValue.DONE) {
                shutDownLatch.countDown();

                // Not interested in the return value, only interested in the
                // exception if one was thrown...
                try {
                    worker.get();
                } catch (InterruptedException | ExecutionException ex) {
                    // Resync the error with the UI, probably using SwingUtilities.invokeLater
                    // and call some error handling method
                    ex.printStackTrace();
                }
            }
        }

    }
}

ReadWorker 类:

public class ReadWorker extends SwingWorker<Void,String> {

     private InputStream is;
     private JTextArea ta;

        public ReadWorker(InputStream is, JTextArea ta) {
            this.is = is;
            this.ta = ta;
        }

    @Override
    protected Void doInBackground() throws Exception {
        byte[] buffer = new byte[4096];
        int bytesRead = -1;
        while (!isCancelled() && (bytesRead = is.read(buffer)) != -1) {
            String text = new String(buffer, 0, bytesRead);
            publish(text);
        }
        return null;
    }

    @Override
    protected void process(List<String> chunks) {
        for (String text : chunks) {
            ta.append(text);
        }
    }
}

写工作者类:

public class WriteWorker extends SwingWorker {

    private OutputStream os;

    private List<String> queue = new ArrayList<String>(25);
    private ReentrantLock queueLock = new ReentrantLock();
    private Condition queueCondition = queueLock.newCondition();

    @Override
    protected Object doInBackground() throws Exception {
        while (!isCancelled()) {
            String text = null;
            while (text == null && !isCancelled()) {
                queueLock.lock();
                try {
                    if (queue.isEmpty()) {
                        queueCondition.await();
                    }

                    if (!queue.isEmpty()) {
                        text = queue.remove(0);
                    }
                } finally {
                    queueLock.unlock();
                }
                if (text != null) {
                    os.write(text.getBytes());
                }
            }
        }
        return null;
    }

     public WriteWorker(OutputStream os) {
            this.os = os;
        }

     public void write(String text) {
            queueLock.lock();
            try {
                queue.add(text);
                queueCondition.signal();
            } finally {
                queueLock.unlock();
            }
     }
}

最后是主类:

public class Main {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {

                MainFrame frame = new MainFrame();
            }
        });
    }
}

我做错了什么,为什么?

你会为此而自责。

你只需要一根线。

任何时候写入文件(或任何流)的 stdin 时,请确保刷新缓冲区。

在您的doInBackground()的方法WriteWorker ,你需要添加:

os.flush();

在您致电os.write(...)

所以你的doInBackground()方法应该是这样的:

@Override
protected Object doInBackground() throws Exception {
    while (!isCancelled()) {
        String text = null;
        while (text == null && !isCancelled()) {
            queueLock.lock();
            try {
                if (queue.isEmpty()) {
                    queueCondition.await();
                }

                if (!queue.isEmpty()) {
                    text = queue.remove(0);
                }
            } finally {
                queueLock.unlock();
            }
            if (text != null) {
                os.write(text.getBytes());
                os.flush();
            }
        }
    }
    return null;
}

暂无
暂无

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

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