I'm working on a program and I'm having problems with printing my results on the TextArea on the fly (similar as you can do with System.out.print("")) and need them to append on the text area. I want to use this as process steper window.
I have tried to call in new Thread and some other stuff, but no success. I'm really stuck here.
Any help would be really appreciated.
Here is the example code. In the StdOut you can see when the code is executed, and at that time it should be also visible in TextArea but it appears on it when the method is complete. It should append the text on TextArea the same time as stdout is executed.
public class Start {
public static void main(String[] args) {
Manager.getInstance();
}
}
public class Manager {
public static Manager instance;
private MyFrame mainFrame;
private Manager(){
mainFrame = MyFrame.newInstance();
mainFrame.setVisible(true);
}
public static Manager getInstance() {
if(instance == null){
instance = new Manager();
}
return instance;
}
public void startMethod() {
for(int i = 0; i < 5000; i++){
doSmething();
if(i == 0){
sendMsg("Start");
}
}
sendMsg("End");
}
private void doSmething() {
try{
Thread.sleep(1);
}
catch (InterruptedException e){
}
}
private void sendMsg(String str){
(new Thread(new MyFrameMsg(mainFrame,str))).start();
mainFrame.setTextArea(str);
System.out.println(str);
}
}
class MyFrameMsg implements Runnable{
private MyFrame mainFrame;
private String str;
public MyFrameMsg(MyFrame _mainComander, String _str) {
mainFrame = _mainComander;
str = _str;
}
@Override
public void run() {
System.out.println(str + " in thread");
mainFrame.setTextArea(str);
}
}
public class MyFrame extends javax.swing.JFrame {
private static MyFrame instance;
public MyFrame(){
initComponents();
instance = this;
}
public static MyFrame newInstance() {
if(instance == null){
new MyFrame();
}
return instance;
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
textArea = new javax.swing.JTextArea();
startButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
textArea.setEditable(false);
textArea.setColumns(20);
textArea.setRows(5);
jScrollPane1.setViewportView(textArea);
startButton.setText("Start");
startButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1)
.addContainerGap())
.addGroup(layout.createSequentialGroup()
.addGap(162, 162, 162)
.addComponent(startButton)
.addContainerGap(181, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(98, Short.MAX_VALUE)
.addComponent(startButton)
.addGap(39, 39, 39)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 129, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
pack();
}// </editor-fold>
// Variables declaration - do not modify
private javax.swing.JButton startButton;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextArea textArea;
// End of variables declaration
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Manager.getInstance().startMethod();
}
public void setTextArea(String str) {
textArea.append(str + System.getProperty("line.separator"));
}
}
You have to Thread your startMethod() like this:
public void startMethod() {
new Thread() {
public void run() {
for (int i = 0; i < 5000; i++) {
doSmething();
if (i == 0) {
sendMsg("Start");
}
}
sendMsg("End");
}
}.start();
}
The problem with your design is following: The AWT-EventQueue fires your ButtonEvent and than creates 5000 Threaded Objects. These will run and update your TextArea, but the TextArea will only be repainted after the AWT-Eventqueue-Thread is released (after creating all 5000 Objects)
And you should not need to Thread your MyFrameMsg class anymore (except they should do more than an short update in the future)