[英]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.