Reputation: 401
I am new to Swing and I am working on a desktop app. Part of the app has a background process running an .exe and then reading the pout of the terminal into a dynamically created JtextArea. I am appending this output to JtextArea (Thread safe). I can see the output in my PrintLn but not on the JTextArea. In fact, JTextRea is frozen and blank. I suspect there is something to do with revalidate and repaint but I just figure out where to place them? Here is the code that does this job. Any help or suggestion is welcome.
progressWindow = new JFrame("Please wait ...");
FlowLayout defFileFlow = new FlowLayout();
progressWindow.setLayout(defFileFlow);
defFileFlow.setAlignment(FlowLayout.TRAILING);
progressWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
progressWindow.setSize(550,680);
progressPane = new JTextArea(30, 80);
DefaultCaret caret = (DefaultCaret)progressPane.getCaret();
caret.setUpdatePolicy(DefaultCaret.OUT_BOTTOM);
progressPane.setLayout(new BorderLayout(500, 500));
progressPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
progressPane.setFont(new Font("Monospaced", 0, 12));
progressPane.setText("Please wait while we crunch some numbers .." + "\n");
JScrollPane scroller = new JScrollPane(progressPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
progressWindow.add(scroller);
scroller.setBounds(0, 0, 500, 500);
JButton cancelButton = new JButton("Cancel Analysis");
progressWindow.add(cancelButton);
progressWindow.setComponentOrientation(ComponentOrientation.UNKNOWN);
progressWindow.setVisible(true);
progressWindow.setAlwaysOnTop(true);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
progressWindow.setLocation(dim.width/2-progressWindow.getSize().width/2, dim.height/2-progressWindow.getSize().height/2);
try {
copyExecutable(defFilePath, selectedModel);
Process p=Runtime.getRuntime().exec("cmd /c dir && cd " + defFilePath + " && dir && "
+ defFileName);
Thread runCMD = new Thread(new Runnable(){
public void run() {
System.out.println("Inside the thread");
try{
InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(isr);
String line=null; // UI magic should run in here @adityapona
while ( (line = br.readLine()) != null){
System.out.println("MIXWILD:" + line);
progressPane.append("MIXWILD:" + line + "\n");
progressPane.setCaretPosition(progressPane.getDocument().getLength());
}
} catch (IOException ioe)
{
ioe.printStackTrace();
}
}
});
runCMD.start();
Important The window closes successfully when the thread runs and returns an exit value of 0.
Upvotes: 0
Views: 223
Reputation: 324128
Process p=Runtime.getRuntime().exec("...);
Thread runCMD = new Thread(new Runnable(){
The process is being run on the Event Dispatch Thread (EDT)
which prevents the GUI from responding to events and repainting itself.
The Process itself should be started from within the Thread. (ie. try just moving the Process statement from outside the Thread to inside the run() method so the Process executes on a separate Thread, not the EDT Thread.)
Read the section from the Swing tutorial on Concurrency in Swing for more information. You may want to consider using a SwingWorker
which was designed for this type of processing. It allows you to invoke a long running task and "publish" results as they become available. This is a better solution than just using a Thread, since the "publish" process will make sure the "append" executed on the EDT.
Edit:
progressPane.setLayout(new BorderLayout(500, 500));
Why would you try to give a text area a layout manager? Doubt it will cause a problem but it is definitely not needed and should not be used.
progressWindow.setComponentOrientation(ComponentOrientation.UNKNOWN);
No need to play with the orientation.
scroller.setBounds(0, 0, 500, 500);
Don't play with the bounds. It is the job of the layout manager to set the size/location of a component.
Upvotes: 1