JTextField Doesn't Update With Thread.sleep() - java

I'm trying to figure out why the text field isn't updating. I'm aware that using SwingWorker will probably fix this problem, but I can't understand why it doesn't work in the first place.
public class waitExample {
private JFrame frame;
private JTextField txtLeadingText;
private String one = "update string 1";
private String two = "update string 2";
private String three = "update string 3";
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
waitExample window = new waitExample();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public waitExample() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
txtLeadingText = new JTextField();
txtLeadingText.setHorizontalAlignment(SwingConstants.CENTER);
txtLeadingText.setText("leading text");
frame.getContentPane().add(txtLeadingText, BorderLayout.SOUTH);
txtLeadingText.setColumns(10);
JButton btnClickMeTo = new JButton("CLICK ME TO UPDATE TEXT");
btnClickMeTo.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
try {
updateOne();
Thread.sleep(1000);
updateTwo();
Thread.sleep(1000);
updateThree();
Thread.sleep(1000);
updateLast();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
frame.getContentPane().add(btnClickMeTo, BorderLayout.CENTER);
}
private void updateOne() {
txtLeadingText.setText(one);
}
private void updateTwo() {
txtLeadingText.setText(two);
}
private void updateThree() {
txtLeadingText.setText(three);
}
private void updateLast() {
txtLeadingText.setText("default text");
}
}
From what I understand, the default Thread will prevent any GUI updates. That shouldn't matter because I am setting the textField BEFORE the Thread.sleep.
Why doesn't the text field update? Shouldn't the text be set, then the Thread wait?
EDIT: As per the answers, the above code has been updated.

You are invoking Thread.sleep(1000); on EDT. This means that when your method will end - only then the repaint() will fire (at some point in time later).
Until then your GUI is freezed.
Consider that this is going on one thread (so processing is straightforward):
txtLeadingText.setText(one);
Thread.sleep(1000);
txtLeadingText.setText(two);
Thread.sleep(1000);
txtLeadingText.setText(three);
Thread.sleep(1000);
...
<returning from updateText()>
<processing other events on button click>
...
// some time later
<Swing finds out that GUI needs repaint: calls rapaint()>
This is what you should do (I didn't compile or test it):
public class MyRunnable implements Runnable {
private List<String> strsToSet;
public MyRunnable(List<String> strsToSet) {
this.strsToSet = strsToSet;
}
#Override
public void run() {
try {
if(strsToSet.size() > 0) {
final String str = strsToSet.get(0);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
txtLeadingText.setText(str);
}
});
Thread.sleep(1000);
List<String> newList = new LinkedList<String>(strsToSet);
newList.remove(0);
new Thread(new MyRunnable(newList)).start();
}
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}
new Thread(new MyRunnable(Arrays.asList(one, two, three))).start();
It is hard to do in Swing but in contrast in dynamically languages (like Groovy) it would go as simple as that (you'll get a better grasp of what is going on):
edt {
textField.setText(one)
doOutside {
Thread.sleep(1000);
edt {
textField.setText(two)
doOutside {
Thread.sleep(1000);
edt {
textField.setText(three)
}
}
}
}
}

The GUI event loop updates the screen, but it can't update the screen until you return.
I suggest you avoid doing any blocking operations in the GUI event thread.

Related

JButton not invoking actionPerformed on any subsequent click in same GUI instance

I have a JButton that will not allow me to perform the same action on any subsequent click on it after the first in the same Swing GUI instance.
JButton Run = new JButton("Run");
Run.setLocation(290, 70);
Run.setSize(120, 30);
buttonPanel.add(Run);
Run.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (Run.isEnabled()) {
errorLabel.setText("");
Result result = JUnitCore.runClasses(Run.class);
errorMessageDisplay(result);
}
}
});
totalGUI.setOpaque(true);
return totalGUI;
}
So far I thought about and tried removing the JPanel and painting all of the buttons back on, and disabling/renabling buttons.
The errorMessageDisplay method is as follows:
public void errorMessageDisplay(Result resultPass) {
if (resultPass.getFailureCount() > 0) {
errorLabel.setForeground(Color.red);
errorLabel.setVisible(true);
errorLabel.setText(" Failed");
}
else {
errorLabel.setForeground(Color.green);
errorLabel.setText(" Passed");
errorLabel.setVisible(true);
}
}
At first glance, the JUnitCore.runClasses(Run.class); call is suspicous. Also, it would be good to know what does the errorMessageDisplay() do. I believe, the problem is with one of these methods.
You can verify this with the following experimental code. Just be careful not to push it into production.
JButton run = new JButton("Run");
run.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (Run.isEnabled()) {
errorLabel.setText("");
System.out.println("Run action peformed.");
}
}
Update Since the errorMessageDisplay() looks okay, it's probably a Threading problem with JUniCore. Thus I'd try the following code:
final ExecutorService executor = Executors.newFixedThreadPool(5); // this runs stuff in background
JButton run = new JButton("Run");
// ..
run.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (Run.isEnabled()) {
executor.execute(new Runnable() { // This is how we run stuff in background. You can use lambdas instead of Runnables.
public void run() {
final Result result = JUnitCore.runClasses(Run.class); // Run.class is different from the current JButton run.
SwingUtilities.invokeLater(new Runnable() { // Now we go back to the GUI thread
public void run() {
errorMessageDisplay(result);
}
});
}
});
}
});

Strange Concurrency Issue in Java Swing

I have a Jframe which is my application's window (appFrame in the following code) that contains a lot of logic and takes like 1 second or so to load. In the meantime I want to show my user a very nice loading frame (initFrame). However, when I run this code, the initFrame does appear but the text in a JLabel on it doesn't appear immediately - it actually doesn't appear at all in the brief moment till the app frame is loaded.
If i comment out all the appFrame, and only launch the initFrame, the text is loaded instantly, no waiting time at all. Why is this so? Might this be a concurrency issue?
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() { //as per best practice for concurrency in swing - see http://docs.oracle.com/javase/tutorial/uiswing/concurrency/
#Override
public void run() {
final JFrame initFrame = new InitFrame();
initFrame.setVisible(true);
final AppFrame appFrame = new AppFrame();
appFrame.setVisible(true);
initFrame.setVisible(false);
initFrame.dispose();
}
});
}
I would separate the frames' creation into two threads. The first, initializing InitFrame. Running this thread and calling isShowing() on the InitFrame object. When it returns true, run the second thread to initialize and show AppFrame.
This will force a happens before relationship between the visibility of the two frames.
class Main {
JFrame initFrame = null;
AppFrame appFrame = null;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initFrame = new InitFrame();
initFrame.setVisible(true);
}
});
while(!initFrame.isShowing()) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
appFrame = new AppFrame();
appFrame.setVisible(true);
initFrame.setVisible(false);
initFrame.dispose();
}
});
}
}
Here's an example of what might be going wrong in your AppFrame.
You can run the test with threading:
java SplashTest true
or without
java SplashTest
When threading is enabled, you see the SplashFrame and AppFrame updating every 250ms, more or less.
When threading is not enabled, you get to see the SplashFrame with no components showing, the app 'hangs' for 4 seconds, then you see the AppFrame.
The example is somewhat contrived, but might give you some ideas.
Note that the SplashFrame has no 'direct' connection to the AppFrame. All communication is through the AppFrameWorkListener interface.
I've also put the 'work' in the AppFrame. But really if there is a lot of processing to be done it should be extracted out of the UI code, run in a separate Thread, and the AppFrame would be notified of progress by the task, in the same way as the SplashFrame currently is.
import javax.swing.*;
class SplashTest {
static boolean useThread = false;
public static void main(String[] args) {
// Pass true at the command line to turn on threading.
// No args, or any value other than true will turn off threading.
if (args.length > 0) {
useThread = new Boolean(args[0]);
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
SplashFrame splashFrame = new SplashFrame();
splashFrame.setVisible(true);
new AppFrame(splashFrame).setVisible(true);
}});
}
private static class BaseFrame extends JFrame {
public BaseFrame() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(200, 200);
setTitle(getClass().getSimpleName());
}
}
private static class SplashFrame extends BaseFrame implements AppFrameWorkListener {
JLabel status;
public SplashFrame() {
setLocation(0, 0);
status = new JLabel("Splash Frame");
getContentPane().add(status);
}
public void appFrameWorkStart() {
status.setText("Work started");
}
public void appFrameWorkProgress(long timeElapsed) {
status.setText("Work has taken " + timeElapsed + "ms so far");
}
public void appFrameWorkDone() {
// http://stackoverflow.com/questions/1234912/how-to-programmatically-close-a-jframe
setVisible(false);
dispose();
}
}
private static class AppFrame extends BaseFrame {
JLabel status;
AppFrameWorkListener listener;
public AppFrame(AppFrameWorkListener listener) {
setLocation(200, 200);
status = new JLabel("App Frame");
getContentPane().add(status);
this.listener = listener;
// None of this 'heavy lifting' should be in a constructor.
if (useThread) {
new Thread(new Runnable() {
#Override
public void run() {
doLotsOfWork(4);
}
}).start();
} else {
doLotsOfWork(4);
onWorkDone();
}
}
private void doLotsOfWork(int workLengthSeconds) {
// We're starting. Ensure onWorkStart is called on the EDT,
// as this method may be called from a different Thread.
invokeOnWorkStartOnEDT();
long start = System.currentTimeMillis();
// Hammer the CPU for "workLengthSeconds" number of seconds.
// And do some contrived progress reporting.
long workLengthMs = workLengthSeconds * 1000;
while (System.currentTimeMillis() - start < workLengthMs) {
long innerStart = System.currentTimeMillis();
// Consume 250ms CPU before issuing progress update.
while (System.currentTimeMillis() - innerStart < 250);
invokeOnWorkProgressOnEDT(System.currentTimeMillis() - start);
}
// We're done now. Ensure onWorkDone is called on the EDT,
// as this method may be called from a different Thread.
invokeOnWorkDoneOnEDT();
}
private void invokeOnWorkStartOnEDT() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
onWorkStart();
}
});
}
private void invokeOnWorkProgressOnEDT(final long timeElapsed) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
onWorkProgress(timeElapsed);
}
});
}
private void invokeOnWorkDoneOnEDT() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
onWorkDone();
}
});
}
private void onWorkStart() {
status.setText("Work Started");
if (null != listener) {
// Tell someone who's interested in the work status.
listener.appFrameWorkStart();
}
}
private void onWorkProgress(long timeElapsed) {
status.setText("Work has taken " + timeElapsed + "ms so far");
if (null != listener) {
// Tell someone who's interested in the work status.
listener.appFrameWorkProgress(timeElapsed);
}
}
private void onWorkDone() {
status.setText("Work Done");
if (null != listener) {
// Tell someone who's interested in the work status.
listener.appFrameWorkDone();
}
}
}
interface AppFrameWorkListener {
public void appFrameWorkDone();
public void appFrameWorkStart();
public void appFrameWorkProgress(long timeElapsed);
}
}
You Should use Java Thread and you can show an interactive Splash Screen (Custom made) to your user in the mean while while your code is generating whatever you want here is a tutorial just take a look
You should use Threads for good and efficient concurrency thats it

How to show a splash-screen, load datas in the background, and hide the splash-screen after that?

I'm designing a simple JavaFX form.
First, I load the JavaFX environment (and wait for it to finish), with something like this :
final CountDownLatch latch_l = new CountDownLatch(1);
try {
// init the JavaFX environment
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JFXPanel(); // init JavaFX
latch_l.countDown();
}
});
latch_l.await();
}
This works fine. (the reason why I need to first load the JavaFX this way, is because it's mainly a Swing application, with some JavaFX components inside, but they are loaded later)
Now, I'd like to add a splash-screen on launch, and displays it while the JavaFX environment loads (and in fact put in on-screen for like 5 seconds, because there are logo, trademark etc.. of the application I need to show)
So I came up with a SplashScreen class, which just displays a JWindow on-screen, like that :
public class SplashScreen {
protected JWindow splashScreen_m = new JWindow();
protected Integer splashScreenDuration_m = 5000;
public void show() {
// fill the splash-screen with informations
...
// display the splash-screen
splashScreen_m.validate();
splashScreen_m.pack();
splashScreen_m.setLocationRelativeTo(null);
splashScreen_m.setVisible(true);
}
public void unload() {
// unload the splash-screen
splashScreen_m.setVisible(false);
splashScreen_m.dispose();
}
}
Now, I want for the splash-screen to load and display itself 5 seconds.
Meanwhile, I want the JavaFX environment to load, too.
So I updated the CountDownLatch like this :
final CountDownLatch latch_l = new CountDownLatch(2); // now countdown is set to 2
final SplashScreen splash_l = new SplashScreen();
try {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// show splash-screen
splash_l.show();
latch_l.countDown();
// init the JavaFX environment
new JFXPanel(); // init JavaFX
latch_l.countDown();
}
});
latch_l.await();
splash_l.unload();
}
So, it's working, but the splash only stays for the JavaFX environment to load, so basically it unloads very quickly (which is normal, given the code I wrote).
How to display the splash-screen for 5 seconds minimum (if the JavaFX loads faster) without freezing the EDT ?
Thanks.
The most significant issue is you're blocking the Event Dispatching Thread, meaning that it can't display/update anything while it's blocked. The same problem applies to JavaFX.
You should, also, never update either from anything other then they respective event queues.
Now, there are any number of ways you might be able to go about this, but SwingWorker is probably the simplest for the time been.
I apologise, this is the entire exposure to JavaFX I've had...
public class TestJavaFXLoader extends JApplet {
public static void main(String[] args) {
new TestJavaFXLoader();
}
public TestJavaFXLoader() throws HeadlessException {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Loader loader = new Loader();
loader.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("state") && evt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
System.out.println("Load main app here :D");
}
}
});
loader.load();
}
});
}
public class Loader extends SwingWorker<Object, String> {
private JWindow splash;
private JLabel subMessage;
public Loader() {
}
protected void loadSplashScreen() {
try {
splash = new JWindow();
JLabel content = new JLabel(new ImageIcon(ImageIO.read(...))));
content.setLayout(new GridBagLayout());
splash.setContentPane(content);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
subMessage = createLabel("");
splash.add(createLabel("Loading, please wait"), gbc);
splash.add(subMessage, gbc);
splash.pack();
splash.setLocationRelativeTo(null);
splash.setVisible(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
protected JLabel createLabel(String msg) {
JLabel message = new JLabel("Loading, please wait");
message.setForeground(Color.CYAN);
Font font = message.getFont();
message.setFont(font.deriveFont(Font.BOLD, 24));
return message;
}
public void load() {
if (!EventQueue.isDispatchThread()) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
loadSplashScreen();
}
});
} catch (Exception exp) {
exp.printStackTrace();
}
} else {
loadSplashScreen();
}
execute();
}
#Override
protected void done() {
splash.dispose();
}
#Override
protected void process(List<String> chunks) {
subMessage.setText(chunks.get(chunks.size() - 1));
}
#Override
protected Object doInBackground() throws Exception {
publish("Preparing to load application");
try {
Thread.sleep(2500);
} catch (InterruptedException interruptedException) {
}
publish("Loading JavaFX...");
runAndWait(new Runnable() {
#Override
public void run() {
new JFXPanel();
}
});
try {
Thread.sleep(2500);
} catch (InterruptedException interruptedException) {
}
return null;
}
public void runAndWait(final Runnable run)
throws InterruptedException, ExecutionException {
if (Platform.isFxApplicationThread()) {
try {
run.run();
} catch (Exception e) {
throw new ExecutionException(e);
}
} else {
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
lock.lock();
try {
Platform.runLater(new Runnable() {
#Override
public void run() {
lock.lock();
try {
run.run();
} catch (Throwable e) {
e.printStackTrace();
} finally {
try {
condition.signal();
} finally {
lock.unlock();
}
}
}
});
condition.await();
// if (throwableWrapper.t != null) {
// throw new ExecutionException(throwableWrapper.t);
// }
} finally {
lock.unlock();
}
}
}
}
}
I found the runAndWait code here

Make method that returns when JButton is pressed

I need to make a method that returns only when a JButton is pressed. I have a custom JButton class
public class MyButton extends JButton {
public void waitForPress() {
//returns only when user presses this button
}
}
and I want to implement waitForPress. Basically, the method should only return when the user presses the button with their mouse. I have achieved similar behavior for JTextField (to return only when user presses Space):
public void waitForTriggerKey() {
final CountDownLatch latch = new CountDownLatch(1);
KeyEventDispatcher dispatcher = new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_SPACE) {
System.out.println("presed!");
latch.countDown();
}
return false;
}
};
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(dispatcher);
try {
//current thread waits here until countDown() is called (see a few lines above)
latch.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(dispatcher);
}
but I would like to do the same thing with JButton.
In advance: Please, if you wish to comment saying that this is not a good idea and that one should simply wait for actionPerformed event on a JButton and then do some action, please realize I already know that and have a good reason for doing what I'm asking here. Please try to only help with what I've asked. Thanks!!
In advance: Please, also realize that implementing actionPerformed also will not directly solve the problem. Because the code will progress even without the button being pressed. I need the program to stop, and only return when the button has been pressed. Here is a terrible solution if I were to use actionPerformed:
public class MyButton extends JButton implements ActionPerformed {
private boolean keepGoing = true;
public MyButton(String s) {
super(s);
addActionListener(this);
}
public void waitForPress() {
while(keepGoing);
return;
}
public void actionPerformed(ActionEvent e) {
keepGoing = false;
}
}
For what it's worth, here is how you can do it with wait() and notify() but yet I feel that there is a deeper problem here. I would not consider this as a satisfying solution:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class TestBlockingButton {
boolean clicked = false;
private Object toNotify;
private void initUI() {
JFrame frame = new JFrame(TestBlockingButton.class.getSimpleName());
JButton button = new JButton("Click me");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
clicked = true;
if (toNotify != null) {
synchronized (TestBlockingButton.this) {
toNotify.notify();
}
}
}
});
frame.add(button);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void waitForProcess() {
toNotify = this;
while (!clicked) {
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
System.out.println("continuing work");
}
public static void main(String[] args) {
final TestBlockingButton test = new TestBlockingButton();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
test.initUI();
}
});
ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
pool.execute(new Runnable() {
#Override
public void run() {
System.out.println("I was doing something and now I will wait for button click");
test.waitForProcess();
System.out.println("User has now cliked the button and I can continue my work");
}
});
}
}
As you asked for an implementation with a mutex, here's what it would be like.
I'm using an ActionListener though, but there's no busy wait in it. If that isn't what you desire, you atleast saw what Burkhard meant ;)
public class MyButton extends JButton implements ActionListener
{
private Semaphore sem = new Semaphore(1);
public MyButton(String text) throws InterruptedException
{
super(text);
addActionListener(this);
sem.acquire();
}
#Override
public void actionPerformed(ActionEvent e) {
sem.release();
}
public void waitForPress() throws InterruptedException {
sem.acquire();
//do your stuff
sem.acquire();
//or just
//waitForPress()
//if you dont want it to end.
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame();
MyButton m = new MyButton("test");
frame.add(m);
frame.pack();
frame.setVisible(true);
m.waitForPress();
//another time, if you only want it to block twice
m.waitForPress();
}
}
But I don't think this is a clean approach, but it doesn't consume CPU-time like a while(isStatementTrue)-implementation.
An important thing here is: you're blocking the main thread with m.waitForPress() but as you wrote you're quite experienced and you know how to handle that.

Calling a Background Thread in Swing

First code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class cos {
public static int a;
private static JLabel labeler;
// public static Runnable r1;
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
a = 0;
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
cos window = new cos();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public cos() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
public void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 205, 194);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel lblTime = new JLabel("Time:");
frame.getContentPane().add(lblTime, BorderLayout.WEST);
final JLabel labeler = new JLabel("");
frame.getContentPane().add(labeler, BorderLayout.CENTER);
JButton btnNewButton = new JButton("New button");
btnNewButton.addActionListener(new ActionListener() {
Runnable r1 = new Runnable() {
public void run() {
while (a <= 10) {
a = a + 1;
labeler.setText(Integer.toString(a));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
public void actionPerformed(ActionEvent arg0) {
Thread threder = new Thread(r1);
threder.start();
// liczniczek bla = new liczniczek();
}
});
frame.getContentPane().add(btnNewButton, BorderLayout.SOUTH);
}
public void licznik() {
while (a < 60) {
a = a + 1;
labeler.setText(Integer.toString(a));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
And now my question. I wanna use code like this:
Runnable r1 = new Runnable(){
public void run(){
licznik();
}
};
But that doesen't work. What i must do to separate this code ? Sorry for my bad english
Sierran.
never use Thread#sleep(int) during EDT, sure if is there only this thread then works correctly (with blockng EDT),
Runnable r1 = new Runnable(){
public void run(){
licznik();
}
};
is wrong than same as you call plain licznik();, you have to wrap that this way
Runnable r1 = new Runnable(){
public void run(){
labeler.setText(Integer.toString(a));
}
};
but again without Thread#sleep(int), you have three choises
1) change Thread to the javax.swing.Timer
2) change Thread to the Runnable#Thread, there you can delaying with Thread#sleep(int), but output to the GUI must be
Runnable r1 = new Runnable(){
public void run(){
labeler.setText(Integer.toString(a));
}
};
3) use SwingWorker, where output is in the EDT and you can use Thread#sleep(int) too
example Thread#sleep(int) during EDT
put all together
EDIT
don't use reserved words as class, method, variable, whatever Name in the Programing languages (meaning cos)
your code works by implements all three options that I post here,
What do you mean "it doesn't work"? It works for me. How are you trying to use this code, and what errors or problems are you having when you run it? Myself, I'd use a SwingWorker though and I'd set the JLabel's text via the SwingWorker's publish/process method pair. To learn more on how to use this, please see this tutorial: Concurrency in Swing
Edit
Actually, an easier way to accomplish what you want is to not use threads or Runnables directly at all but to use a Swing Timer as they're built for just this case. For more on this, please check out the Swing Timer Tutorial
I gather that you want the function licznik() to run in a separate thread. You create a Runnable, but you have to do something more to make its run() method execute. There are a couple of ways to do this:
Runnable r1 = new Runnable(){
public void run(){
licznik();
}
};
new Thread(r1).start();
or you can just subclass Thread directly:
Thread r1 = new Thread(){
public void run(){
licznik();
}
};
r1.start();
Runnable interface has no method licznik(). You can create class that implements Runnable with licznik() method.
Or if you do not need to reuse this method and use it just once, then the fastest way is to move its implementation inside new Runnable() block
Runnable r1 = new Runnable(){
public void run(){
this.licznik();
}
public void licznik(){
while (a < 60){
a = a + 1 ;
labeler.setText(Integer.toString(a));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
Look on GitHub under at https://github.com/greggwon/Ham. Look at the source code in https://github.com/greggwon/Ham/blob/master/SwingUtil/src/org/wonderly/swing/ComponentUpdateThread.java to see how I've packaged this whole detail into a single class which uses anonymous inner classes to do the work. It would be possible to change this to lambdas now, but I have not used Java in several years and thus haven't made that change.
new ComponentUpdateThread( new Action[] { add, del, edit } ) {
public void setup() {
super.setup();
list.setEnabled(false);
list.clearSelection();
}
public Object construct() {
try {
Vector v = remote.getData();
Collections.sort( v );
return v;
} catch( Exception ex ) {
reportException(ex);
}
return null;
}
public void finished() {
try {
Vector v = (Vector)getValue();
if( v != null ) list.setListData(v);
} finally {
super.finished();
list.setEnabled(true);
edit.setEnabled(false);
del.setEnaled(false);
}
}
}.start();
With this style of work, you can use final values from surrounding blocks or other class visible data to control various aspects of what happens before, during and after background thread execution.
I've change this code around over the years in various ways and there are other variations of this that exist.
The arguments to the ComponentUpdateThread constructor are controls/actions to be "disabled" while the background thread is running. Other enable/disable activities can be more literally embedded into the activities in setup() and finished() (which are run in the AWT event thread) before "construct" is run in the background thread.

Categories