what happens if i modify my gui inside a thread created in the edt?
When i say "created in the edt" i actually say that the thread declaration and its starts are in a block of code surrounded by:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
Thread t= new Thread(new Runnable(){
public void run(){
txtField.setText("setting...");
}
});
t.start();
}
}
will this modify my gui without side effects? or should i call again invokeLater inside Thread "T"?
It doesn't matter whether you instantiate and run the thread in EDT. It will be a new thread, running independently from EDT, and therefore it will not be safe to modify the GUI from it. All Swing modifications must be done using invokeLater().
Related
I can't understand what exactly is happening behind the scene.
If I have a main method like below, does it mean, that I have 2 threads?
One main thread and one thread for the events like paintComponent or listeners etc?
If so, what exactly happens in the main thread then?
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Ampelsteuerung frame = new Ampelsteuerung();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}`
I deleted the EventQueue and tested it without, couldn't see any difference.
If you read the description of SwingUtilities.invokeLater() you'd understand the reasons. It's all about the synchronization between AWT events and the GUI threads
This will happen after all pending AWT events have been processed.
This method should be used when an application thread needs to update
the GUI....If invokeLater is called from the event dispatching thread -- for example, from a JButton's ActionListener -- the doRun.run() will still be deferred until all pending events have been processed
Therefore "nothing" seems to happen if no pending event exists as in your case.
i have problem in java and I do not know him and I resolved.
I created a simple program that inserts into the text JPanel using for and sleep function.
Like this(This is an example):
public class example{
JFrame frame....
..
..
public example(){
//ini frame and label.. then..
String s = "abcqweewqewqewqewqweqwqeweqweqwq";
//DO ANIMATION
try
{
for(int i = 0;i<s.length();i++)
{
JLABEL.append(String.valueOf(s.charAt(i)));
Thread.sleep(10);
}
}catch(Exception ex){}
}
public static void main.......{
new example();
}
}
It works perfectly (writes characters after a certain time interval)
But, if i call this main using other class-So waiting until everything renders and then the window appears (so does not animation).
Where is a problem? I hope, you understand me.
Swing is single threaded, and properly written swing code runs in the event dispatch thread. Your sample breaks the threading rule by creating the GUI outside the EDT, and also runs the loop in the main thread. Normally, when created correctly in the EDT, or as a response to an event from a button click or similar, the loop blocks the event dispatch thread so that no drawing can happen until the loop has completed.
You get that behaviour if you initialize the GUI in the event dispatch thread:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new example()
}
});
}
The proper way, instead of sleeping in the EDT, is using a Swing Timer.
To sum the above: your code appears to work only because it has the bug that it runs some of the UI code outside the event dispatch thread.
I have a thread inside an invokeLater method in Blackberry like:
startButton.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field arg0, int arg1) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Thread thread = new Thread(){
public void run() {
uploadFile();
}
};
thread.start();
}
});
}
I have a thread because I want to run that function in the background and want to be able to do other stuff while its doing its job. What I am wondering is if this is a good approach. Do I really need the invokeLater in this case ?
Short answer: no.
Long answer:
InvokeLater puts the Runnable on the event queue so that, in time, when the event loop sees the Runnable it will execute it on the event thread. Since you are calling invokeLater in the fieldChanged method of a FieldChangeListener, you are calling it from the event thread. Unless what you want to do is delay the start of your thread to some unknown later time then no you don't need to use invokeLater.
im calling invokeLater direcly from button on actionPerformed with this code:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int temp = (jComboBox1.getSelectedIndex() + 1);
heavyProccesingFunction();
}
});
}
and that still freezes the GUI. Why? I get the same result without using the invokelater function.
should I Use
Thread queryThread = new Thread() {
public void run() {
instead?
Edit:
Thanks, new thread should be used.
invokeLater still ends up running the code on the dispatcher thread - just later. The aim of invokeLater is to allow background threads to post work on the event dispatcher thread.
It sounds like you should indeed create another thread - or use a thread pool for the same sort of effect, or SwingWorker for example. Whatever you do, you need to avoid running your slow method on the event dispatcher thread.
So my program has multiple classes and after one of them has run, it'd like it so it appends the text area in the main class GUI with a 'finished' message
ta.append("Search Complete\n");
and this is the code that needs to complete
statCl.addActionListener(new ActionListener(){
public void actionPerformed (ActionEvent e) {
try {
ta.append("Searching...\n");
task.execute();
} catch (Exception IOE) {}
}
});
So it is in the class where task where actual code runs.
Any advice or help would be amazing, thanks.
If the task.execute() method doesn't start launch an operation in another thread, then the GUI will be freezed, and nothing will apear in the text area until the operation is finished. So you might just have
ta.append("Searching...\n");
task.execute();
ta.append("Finished");
If the operation is launched in a new thread, then this thread should append in the text area, but it should make sure this append is done in the event dispatch thread (EDT). Your code could thus look like this :
public class Task {
private JTextArea ta;
public Task(JTextArea ta) {
this.ta = ta;
}
public void execute() {
Thread t = new Thread(new Runnable() {
// perform the long operation
// at the end, update the text area, in the EDT
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ta.append("finished");
}
});
}
t.start();
}
}
You might also look at SwingWorker, which is designed just for that (and other things like progress update). There is a code example in its class javadoc which does just what you're trying to do.
You should not be performing long-running task on EDT (event dispatching thread):
http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
Swing does all it's work on EDT, so you should not block EDT, e.g. run intensive tasks on it. Note: all event handlers are executed on EDT.
So there are two challenges:
Run intensive tasks in a background thread.
Update GUI, which must be done on EDT.
Use SwingWorker to solve this two issues.