In a swing application, I have a popup jDialog which pops up with a jlabel that says "Hang on 5 seconds."
After 5 Seconds, the label should change to "Okay, now I'm done." And a button should appear allowing the user to click continue.
In the example action below (linked to a button which causes the popup), the popup appears as it should but it is blank instead of saying "Hang on 5 seconds." Then after 5 seconds everything updates and the labels are there and the button too. So what's going on? Is the thread sleeping before a repaint or something?
#Action
public void popUp() {
popUpDialog.setSize(300,200);
popUpDialog.setLocationRelativeTo(null);
popUpDialog.setVisible(true);
popUpLabel.setVisible(true);
popUpLabel.setText("Working, hang on a sec....");
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
popUpLabel.setText("Okay Now I'm Done.");
popUpBut.setVisible(true);
}
EDIT: So I tried this, in an effort to use a swing timer in place of thread sleeping:
#Action
public void popUp() {
popUpDialog.setSize(300,200);
popUpDialog.setLocationRelativeTo(null);
popUpDialog.setVisible(true);
popUpLabel.setVisible(true);
popUpLabel.setText("Working, hang on a sec....");
Timer timer = new Timer(speed, this);
timer.setInitialDelay(pause);
timer.start();
popUpLabel.setText("Okay Now I'm Done.");
popUpBut.setVisible(true);
}
Obviously I'll need more code to finish the timer, but right off the bat I get a symbol not found, variable: timer error. What's that all about? Am I doing it wrong?
Edit 2: I changed the timer declaration and solved one problem but created another. Now I am getting the symbol not found error in regards to speed. I have never used a swing timer before and don't know how to use them. The java tutorial on the topic is convoluted and difficult to understand. Can any of you point me to a simple, clear example of a timer so I can learn from that and figure out what I need to do?
If your code modifying your Swing component's state is on the EDT here (it should be), then no repainting of the label with the first text will take place even if you do call repaint(), because all other EDT requests queued before the last repaint need to complete before you reach that repaint, and your code here is one of those queued EDT events.
If you call repaint, it adds a repaint to the queue, it doesn't repaint right away. Your actions here will result in a 5 second wait, with the label before the next repaint having only the text you last set it to (as code queued on the EDT is executed fully before going to what next is queued).
Try using a Swing Timer, events fired from the Swing Timer are already executing on the EDT, so it's pretty much what you need, one event here where you set the text initially, and another event fired by the Swing Timer to change the text after 5 seconds.
Edit, example of Swing Timer firing once, after 5 seconds as requested by author:
// set first jlabel text here
ActionListener task = new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("This is on the EDT after 5 seconds, " +
"well depending on if I'm used with a Timer, and if " +
"the right options are set to that Timer");
// set second jlabel text here
}
};
Timer timer = new Timer(5000 , task);
timer.setRepeats(false);
timer.start();
I have a popup jDialog which pops up with a jlabel that says "Hang on 5 seconds."
You have a dialog that is visible BEFORE:
you set the text on the label
the Thread.sleep()
The code following popupDialog.setVisible(true) is not executed until the dialog is closed. Reorder your code.
Also, you need to use a Swing Timer to schedule the changing of the text.
popUpLabel.setVisible(true);
popUpLabel.setText("Working, hang on a sec....");
should be
popUpLabel.setText("Working, hang on a sec....");
popUpLabel.setVisible(true);
and AFTER this you should set the dialog to visible.
You could also keep the order of your code as you have it now - and force the label / panel to update. Though this seems like less of a logical choice in this scenario
Related
I im creating a simple testing app that runs a check every hour on the selected directory/s using thread.sleep() through JFileChooser. But when i select the directory and the method runs the ui panel goes grey and the swing bits disappear. The thread seems to be putting the ui to sleep as well as the method its calling.
if (option == JFileChooser.APPROVE_OPTION) {
selectedDirectory = chooser.getSelectedFiles();
try {
while (true) {
runCheck(selectedDirectory);
Thread.sleep(1000*5);//1000 is 1 second
}
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
e1.printStackTrace();
}
}
Im looking for a way around this issue so that i can print the results of the checks being run in the ui .setText(result)
You are correct about the code putting the UI to sleep. Since sleep is called on the Event Dispatch Thread (the thread responsible for running the gui) the UI stops processing events and 'goes to sleep'.
I think what you want is a javax.swing.Timer.
Timer t = new Timer(1000 * 5, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do your reoccuring task
}
});
This will cause your reoccurring task to be performed off of the EDT, and thus it wont leave your ui unresponsive.
If the code you have posted runs on the EventDispatchThread, then there is no way Swing can redraw the GUI. You're blocking (sleeping in) the thread that's supposed to handle that!
This is because you are running you check in the main GUI thread and are using an infinite loop. This check is a background task and should be executed in it's own thread so that the GUI can still receive and react to input by the user.
You also do not need to write your own implementation, Java has a Timer object.
Edit: There is also a Swing specific Timer object. This will have the action occur in the GUI thread, so if your task is long, it can cause the GUI to still lock up while the action is occurring (but not while it is waiting).
I'm trying to display an image (iconLabel4) for 5 seconds and then display another image (imageLabel) on top of it after. Why doesn't the code work as intended?
When I run it, what happens is this: I press the button "Bathe" and nothing happens.
I would appreciate any help! Thank you.
Code:
JButton bathe = new JButton("Bathe");
bathe.setBounds(370, 450, 80, 25);
bathe.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent event){
long startTime=System.currentTimeMillis();
String actionCommand = event.getActionCommand();
if (SHOW_ACTION.equals(actionCommand)){
while (System.currentTimeMillis() - startTime < 5000) {
iconLabel4.setVisible(true);
} }
iconLabel4.setVisible(false);
imageLabel.setVisible(true);
repaint();
};
});
bathe.setActionCommand(SHOW_ACTION);
panel.add(bathe);
Don't use a while loop for timing. Use a javax.swing.Timer. See more at How to Use Swing Timers. Here's the basic construct
Timer (int delayInMillis, ActionListener listener)
where delayInMillis is the millisecond delay between "ticks". Every tick will fire an ActionEvent, just like a button press would. So the listener you pass to the timer, had the actionPerformed method that will be called every tick.
Just use one JLabel and two ImageIcons. When you try to set component visible and not visible after the containter is already visible, you need to revalidate() and repaint() the container. That's not the correct approach though. Just use one label, and make use of the method JLabel.setIcon(ImageIcon) when you want to change the icon.
Don't use null layouts. Learn to use layout managers and let them do the positioning for you. See more at Laying out Components Within a Container
Just a suggestion, you can use Thread.sleep(5000).
Considerations: Thread.sleep() is inaccurate. How inaccurate depends on the underlying operating system and its timers and schedulers. I've experienced that garbage collection going on in parallel can lead to excessive sleep. - StackOverflow
But if you don't mind a few milliseconds here and there, its easier.
I have a JLabel which I want to change momentarily, here is the code I have written to do so:
infoLabel.setText("Added");
try {
TimeUnit.MILLISECONDS.sleep(300);
}
catch(InterruptedException ex)
{
}
infoLabel.setText("Action"); //funny part is when I comment this line it works
My default text for the label is 'Action'
Swing is a single threaded frame work, that means, if you do anything that stops this thread, then it can't respond to any new events, including paint requests.
Basically, TimeUnit.MILLISECONDS.sleep(300) is causing the Event Dispatching Thread to be put to sleep, preventing it from processing any new paint requests (amongst other things).
Instead, you should use a javax.swing.Timer
Take a look at
Concurrency in Swing
How to use Swing Timers
For more details
For example...
infoLabel.setText("Added");
Timer timer = new Timer(300, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
infoLabel.setText("Action");
}
});
timer.setRepeats(false);
timer.start();
Note, 300 milliseconds is a really short time, you might like to start with a value a little larger like 2000, which is 2 seconds ;)
You're sleeping the Swing event thread putting the entire GUI to sleep. Don't do that. Use a Swing Timer instead.
Your application is run on a single thread, so when you sleep the thread, you prevent it from making any GUI updates.
Are you sure you are doing things properly? By doing everything (including sleep) in the GUI thread, it will always be busy and never get back to Java in order to let the GUI be redrawn.
Search for EDT (Event dispatch thread) for more info. Here is one question on the subject: Processing code doesn't work (Threads, draw(), noLoop(), and loop())
I have a JTable, where a user can select a single row. If that happens, i want to "highlight" another part of the page for a short time to indicate that this is the part of the page that changed after the user interaction.
So my question is: What's the best way to achieve this? At the moment i did it by setting the background color of that panel and starting a SwingWorker which sets the Color back after a short delay. It works as intended, but is it a good idea to use a SwingWorker like that? Are there any drawbacks to that approach? How would you solve this?
Thanks in advance.
I guess a Swing Timer would be a better option as it reuses a single thread for all scheduled events and executes the event code on the main event loop. So, inside your SelectionListener code you do:
// import javax.swing.Timer;
final Color backup = componentX.getBackground();
componentX.setBackground(Color.YELLOW);
final Timer t = new Timer(700, new ActionListener() {
public void actionPerformed(ActionEvent e) {
componentX.setBackground(backup);
}
});
t.setRepeats(false);
t.start();
I recommend a swing Timer (javax.swing.Timer). (do NOT use the Timer class in Java.util)
This is where you make the timer:
Timer t = new Timer(loopTime,actionListener)//loopTime is unimportant for your use of this
t.setInitialDelay(pause)//put the length of time between starting the timer and the color being reverted to normal
t.setRepeats(false);//by default, timer class runs on loop.
t.start();//runs the timer
It probably makes sense to hold on to a reference to the timer, and then just call t.start when you need it.
You need to implement an action listener to handle the timer events. I can edit this if you don't know how to do that, but as you are already doing stuff with Swing I figure it shouldn't be a problem.
I have function like this in Java Swing app. I need after click on button call many function in intervals and in cycles. Function must be called inside jbutton because I have some global parameters in View that are used in jbutton function. Can you please help me how can I create time delay between calling functions and how to display remaining time in jLabel?
private void jButton1MouseClicked(java.awt.event.MouseEvent evt) {
statusMessageLabel.setText("Proccess started.");
for(int i=0;i< cycles;i++) {
//display remaining time
jLabelTimer.setText("00:09:59");
// after time call many functions and then go again
manyFunctions();
} catch (Exception e) {
System.out.println(e);
}
statusMessageLabel.setText("Proccess ended.");
}
}
I agree with Howard's recommendation that a Swing Timer could work well here (1+), but my other concern with your code is here:
manyFunctions();
What exactly is going on at this spot? Are you calling lots of code that is time/cpu-consuming? If so, you will need to take care not to call this on the main Swing thread, the EDT, but rather call it in a background thread, but at the same time taking are to update Swing components only on the EDT. This can be simplified by using a SwingWorker, and you can read up more on this here: Concurrency in Swing
It sounds like you want to have a look at swing timers. With those you can schedule single calls or do them periodically.
This way you can also add a timer which resets your label text periodically.