Correct. When those lines are executed on the event thread things are done like:
1) textField.setText("Loading started...");
2) String page = loadUrl();
3) textField.setText("...Loading done");
4) update screen
And that gives the observed result.
You need to call loadUrl in a separate thread, but still update textField on the event thread as Swing components are usualy not threadsafe.
Example:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class GuiPinger extends JFrame {
private JTextField tf;
private JTextArea ta;
private JButton btn;
public GuiPinger() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setTitle("Pinger");
setLayout(new BorderLayout());
tf = new JTextField();
JPanel top = new JPanel();
top.setLayout(new BorderLayout());
top.add(new JLabel("Host: "), BorderLayout.WEST);
top.add(tf, BorderLayout.CENTER);
getContentPane().add(top, BorderLayout.NORTH);
ta = new JTextArea();
getContentPane().add(new JScrollPane(ta), BorderLayout.CENTER);
btn = new JButton("Ping");
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ta.setText("");
Thread t = new Thread(new Runnable() {
public void run() {
try {
Process p = Runtime.getRuntime().exec(new String[] { "ping", tf.getText() });
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while((line = br.readLine()) != null) {
final String line2 = line + "\n";
EventQueue.invokeLater(new Runnable() {
public void run() {
ta.append(line2);
}
});
}
p.waitFor();
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e.getMessage());
} catch (InterruptedException e) {
JOptionPane.showMessageDialog(null, e.getMessage());
}
}
});
t.start();
}
});
getContentPane().add(btn, BorderLayout.SOUTH);
setSize(800, 600);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new GuiPinger();
f.setVisible(true);
}
});
}
}
The long running thing (here excuting an external ping command) are done in a thread.
When the thread need to update the GUI it uses EventQueue.invokeLater, which will cause it to be done in the event thread.
Another example:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Paging extends JFrame implements ActionListener {
private JTextField txt;
private JButton btn;
public Paging() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new BorderLayout());
txt = new JTextField();
txt.setText("");
getContentPane().add(txt, BorderLayout.CENTER);
btn = new JButton("Vis nyt billede");
btn.addActionListener(this);
getContentPane().add(btn, BorderLayout.SOUTH);
this.setSize(300, 300);
}
public void load(String s) {
txt.setText(s);
}
public void actionPerformed(ActionEvent ev) {
if (ev.getSource() == btn) {
T t = new T(this);
t.start();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Paging f = new Paging();
f.setVisible(true);
}
});
}
}
class T extends Thread {
private static int n = 0;
private Paging pag;
public T(Paging dn) {
this.pag = dn;
}
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
pag.load("Nu viser vi billede af nogle pausefisk");
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
n++;
pag.load("Nu viser vi et rigtigt billede nummer " + n);
}
});
}
}
Hello Arne!
I followed you example and did it like:
public void actionPerformed(final ActionEvent e)
{
textfield.setText"Loading started...");
T t = new T("...loading done!");
t.start();
}
....
class T extends Thread
{
String message;
public T(String m)
{
message = m;
}
public void run()
{
loadUrl();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
textfield.setText(message); }
});
}
}
Seems to work fine!!
If you see anything bad or something I did not get right just let me know!
How ever "mange tak"!
My best regards, really good examples you provided!!
Btw give a svar so I can reward you!
I would probably let the thread write both messages to be consistent.
But that is style not function.