It's impossible to 100% as you've not provided any evidence to support how the code is executed, but I'm assuming that when you start the Thread
, you also open the second frame.
This is probably a bad idea. Instead, you could use a SwingWorker
which will allow you to execute the script in the background, freeing up the UI thread.
When the SwingWorker
completes, you would then create and show the second window passing the result of the script to it...
public class ExecuteWorker extends SwingWorker<String, String> {
private String can, pad, pathfile;
public ExecuteWorker(String can, String pad, String pathfile) {
this.can = can;
this.pad = pad;
this.pathfile = pathfile;
}
@Override
protected String doInBackground() throws Exception {
ProcessBuilder pb = new ProcessBuilder("testpad", "-i", "-c" + can, "-n" + pad, pathfile);
pb.redirectErrorStream(true);
StringJoiner sj = new StringJoiner("\n");
Process p = pb.start();
try (InputStreamReader reader = new InputStreamReader(p.getInputStream());
Scanner scan = new Scanner(reader)) {
while (scan.hasNextLine()) {
String text = scan.nextLine();
System.out.println(text);
sj.add(text);
}
}
return sj.toString();
}
@Override
protected void done() {
try {
String text = get();
// Create and show second UI here...
} catch (Exception e) {
}
}
}
Have a look at Concurrency in Swing and Worker Threads and SwingWorker for more details. I'd also have a look at The Use of Multiple JFrames, Good/Bad Practice? and consider using a CardLayout
instead, see How to Use CardLayout for more details
A alternative approach might be to use a Producer-Consumer pattern, where the SwingWorker
is the producer and we use a interface
which acts a contract for the consumer. In this way, you UI could implement
the consumer contract and be notified when new content was made available
public interface Consumer {
public void consume(String text);
}
public class ExecuteWorker extends SwingWorker<String, String> {
private String can, pad, pathfile;
private Consumer consumer;
public ExecuteWorker(Consumer consumer, String can, String pad, String pathfile) {
this.can = can;
this.pad = pad;
this.pathfile = pathfile;
}
@Override
protected void process(List<String> chunks) {
for (String text : chunks) {
consumer.consume(text);
}
}
@Override
protected String doInBackground() throws Exception {
ProcessBuilder pb = new ProcessBuilder("testpad", "-i", "-c" + can, "-n" + pad, pathfile);
pb.redirectErrorStream(true);
StringJoiner sj = new StringJoiner("\n");
Process p = pb.start();
try (InputStreamReader reader = new InputStreamReader(p.getInputStream());
Scanner scan = new Scanner(reader)) {
while (scan.hasNextLine()) {
String text = scan.nextLine();
System.out.println(text);
publish(text);
sj.add(text);
}
}
return sj.toString();
}
}
This means you could start the SwingWorker
AND setup the new UI at the same time, it also means you don't need to wait for the process to exit before getting output from it.
In the above example, we use the publish
/process
functionality of the worker to synchronise updates to the UI thread, making it safe to update the UI components from.
Oh, and unless you wrap the output text in HTML, JLabel
is probably not your best bet, maybe consider using a JTextArea
instead