#java
#java
Вопрос:
Я написал программу, которая выполняет команду cmd и выводит выходные данные на «консоль» программы. Я использовал поток для печати выходных данных без замораживания программы. Я хочу иметь возможность видеть вывод в реальном времени.
Что с этим не так, и я не могу найти решение для этого, так это то, что часть в initialize
сразу после executeCommand
вызова метода выполняется сразу после ExecuteCommand . Что я хочу иметь возможность сделать, так это выполнить остальную часть инициализации, как только поток перестанет выполняться. Я не могу этого сделать, не заморозив всю программу.
Я использовал метод объединения потоков и аналогичный, но мое приложение просто полностью зависает.
Это мой основной класс
private String genCmd2;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ConvertGUI window = new ConvertGUI();
window.frmConvert.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public ConvertGUI() {
initialize();
}
private void initialize() {
// Execute a generated command concurrently
genCmd2 = "ping google.com -n 5";
executeCommand(genCmd2, genCmdTextArea);
//CODE TO RUN AFTER EXECUTE COMMAND IS FULLY FINISHED
//NOT RIGHT AFTER executeCommand method is called
}
public static void printToTheConsole(JTextArea console, String message) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
console.append(message);
console.validate();
}
});
}
private static void executeCommand(String command, JTextArea console) {
Runnable r = new CommandLineRunnable(command, console);
t = new Thread(r);
t.start();
}
Мой исполняемый класс, который выполняет команду и выводит данные на консоль
public class CommandLineRunnable extends ConvertGUI implements Runnable {
private String generatedCommand;
private JTextArea console;
public CommandLineRunnable(String command, JTextArea console) {
this.generatedCommand = command;
this.console = console;
printToTheConsole(console, command);
}
@Override
public void run() {
StringBuilder output = new StringBuilder();
BufferedReader reader;
Process process;
try {
process = Runtime.getRuntime().exec(generatedCommand);
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
output.append(line "n");
printToTheConsole(console, line "n");
}
printToTheConsole(console, "n--------------------------Success!--------------------------n");
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Ответ №1:
Если вы хотите выполнить печать на консоль, обновить JTextArea во время и после того, как одна из ваших выполняемых # задач была (не) успешно выполнена, вы могли бы реализовать интерфейс и предоставить его вашему конструктору Runnables
Рассмотрим следующий пример, в котором создается экземпляр класса CommandLineRunnable со строкой аргументов ‘aCommand’ в качестве команды, объектом JTextArea ‘console’ и новым анонимным классом ResponseEvent в качестве его параметров.
Обратите внимание, что из-за дублирования в анонимном классе, если вы выполняете несколько команд, скорее всего, вы не захотите создавать экземпляр анонимного класса несколько раз и могли бы просто вставить код printToTheConsole внутри методов функционального интерфейса
public static void main(String[] args) {
JTextArea console = new JTextArea();
/**
* JTextArea init code here
*/
executeCommand("aCommand", console, new ResponseEvent() {
@Override
public void onSuccess(JTextArea console, String response) {
printToTheConsole(console, response);
}
@Override
public void onUpdate(JTextArea console, String response) {
printToTheConsole(console, response);
}
@Override
public void onFailure(JTextArea console, String response) {
printToTheConsole(console, response);
}
});
}
private static void printToTheConsole(JTextArea console, String message) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
console.append(message);
console.validate();
}
});
}
private static void executeCommand(String command, JTextArea console, ResponseEvent event) {
Runnable r = new CommandLineRunnable(command, console, event);
Thread thread = new Thread(r);
thread.start();
}
@FunctionalInterface
private interface ResponseEvent {
default void onSuccess(JTextArea console, String response) {
}
default void onUpdate(JTextArea console, String response) {
}
default void onFailure(JTextArea console, String response) {
}
}
public static class CommandLineRunnable implements Runnable {
private final String command;
private final ResponseEvent event;
private final JTextArea console;
public CommandLineRunnable(String command, JTextArea console, ResponseEvent event) {
this.command = command;
this.console = console;
this.event = event;
}
public ResponseEvent getEvent() {
return event;
}
@Override
public void run() {
Process process;
BufferedReader reader = null;
try {
process = Runtime.getRuntime().exec(getCommand());
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
getEvent().onUpdate(getConsole(), line "n");
}
getEvent().onSuccess(getConsole(), "n--------------------------Success!--------------------------n");
} catch (IOException e) {
getEvent().onFailure(getConsole(), "n--------------------------Failure!--------------------------n");
}
}
private JTextArea getConsole() {
return console;
}
private String getCommand() {
return command;
}
}
После выполнения, которое может произойти в любое время, будет выполнена выполняемая функция#run().
Код будет запущен и будет вызван либо метод ResponseEvent#onSuccess, либо метод ResponseEvent#OnFailure
Затем вы можете обрабатывать ответы так, как хотите, возможно, обновив одну из ваших JTextAreas
Комментарии:
1. Я не хочу выводить данные на консоль после успешного выполнения одной из моих выполняемых задач. Я хочу вывести на консоль, как только какой-либо вывод будет обнаружен во время выполнения команды, в реальном времени. Что я хочу сделать после завершения задачи, так это выполнить код после вызова ExecuteCommand. Что-нибудь вроде System.out.println(«Привет») должно ждать, пока поток завершит свою работу. Если вы посмотрите, что находится внутри initialize() , там есть 2 строки комментариев. Я хочу, чтобы это подождало, пока поток не завершится.
2. @LazioTibijczyk хорошо, я сделал это более применимым к вашим обстоятельствам 🙂