如何实时读取和写入进程,并在JTextArea中实时显示输出?(Java Swing)
我复制并修改了此处发布的答案代码: 我的代码的问题是,它只在代码启动时工作一次。任何后续的write调用都不会起任何作用 这是我的密码: 大型机类如何实时读取和写入进程,并在JTextArea中实时显示输出?(Java Swing),java,multithreading,swing,io,Java,Multithreading,Swing,Io,我复制并修改了此处发布的答案代码: 我的代码的问题是,它只在代码启动时工作一次。任何后续的write调用都不会起任何作用 这是我的密码: 大型机类 public class MainFrame extends JFrame { private JTextArea Output; private JScrollPane outputScrollPane; private JButton clickMe; private ProcessThread proces
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();
}
}
}
我做错了什么?为什么?你会为此自责的 你只需要一句话 任何时候,当您向stdin写入文件(或任何流)时,请确保刷新缓冲区。 在
WriteWorker
的doInBackground()
方法中,您需要添加:
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;
}
顺便说一句,这个过程将是一个国际象棋引擎。我需要向它发送命令,然后实时显示它的评估结果。可以从这里下载引擎exe:当我发送命令“uci\n”时,引擎的响应不会显示在JTextArea上
@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;
}