Как я могу читать и записывать процесс в режиме реального времени и отображать вывод в JTextArea в режиме реального времени? (Java качели) - PullRequest
0 голосов
/ 09 марта 2020

Я скопировал и изменил код ответа, размещенный здесь: Печать вывода процесса на JTextArea через клиентский сервер Сеть в java

Проблема с моим кодом состоит в том, что он работает только один раз когда код запускается. Любые последующие звонки на запись просто ничего не сделают.

Вот мой код:

Класс 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);
    }
}

Класс Process Thread:

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

Что я сделал не так и почему?

1 Ответ

0 голосов
/ 09 марта 2020

Ты будешь пинать себя за это.

Тебе просто нужна была одна строка.

Каждый раз, когда ты пишешь на стандартный файл (или любой другой поток) убедитесь, что вы буферизуете sh буфер.

В вашем 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...