Doing Live/Dynamic changes in Swing - java

I am making a game having squares in it (a grid of panels) and when the game ends there is an algorithm that changes the color of the panels one by one in a "live" fashion where the user watches the squares change color slowly. I try something like:
Thread.sleep(1000);
grid.getComponent(boxNumber).setBackground(Color.YELLOW);
Thread.sleep(1000);
grid.getComponent(boxNumber).setBackground(Color.ORANGE);
Although the color of a box changes to Yellow, it does not change to Orange afterwards. Anyone have any ideas? Hope I was able to be clear.

Read the section from the Swing tutorial on Concurrency to understand why you should not be using the sleep() method.
One solution is to use a SwingWorker, then you can 'publish' the color of the component so it can be updated properly on the EDT and you can invoke the sleep() method in the worker as well.

These need to happen on the Swing event thread. call set background via:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
grid.getComponent(boxNumber).setBackground(Color.ORANGE);
}
});
Note, your Thread.sleep() should not be in the event thread (or directly from within a Swing event listener (ActionListener, WindowListener, etc).
It would also be prudent to look the Swing Timing Framework which is specifically for things like this.

-Generally its not a good idea to do Thread.sleep(1000); in the EDT. You should try using Timers.
-You also need to call revalidate()/validate() and repaint() afterward.
So maybe something like this:
Timer yellowTimer = new Timer(1000,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jtp.setBackground(Color.YELLOW);
//call revalidate()/validate() and repaint() afterward
jtp.revalidate();
jtp.repaint();
}
});
yellowTimer.setRepeats(false);
Timer orangeTimer = new Timer(2000,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jtp.setBackground(Color.ORANGE);
//call revalidate()/validate() and repaint() afterward
jtp.revalidate();
jtp.repaint();
}
});
orangeTimer.setRepeats(false);
yellowTimer.start();
orangeTimer.start();

Related

Wait a few seconds in Swing

I need to wait a few seconds between invoking two different methods in a program with Swing interface. Those methods are not related to the GUI.
firstMethod();
//The interface is changed by other methods
...
//I want to Wait five seconds
secondMethod();
I have tried using a Swing Timer but it does not work. Apparently, the Timer starts but is a non-blocking action, so secondMethod() is executed immediately. I can use sleep(), but that freezes the GUI for those five seconds, so the interface is not updated until after that, which I would prefer to avoid.
I have found here some recommendations to use Future<V> and I have read the Javadoc but I have never used ExecutorService before and I am afraid I may write a too complex piece of code for something that simple.
Any idea on how to do it?
Sounds like your code is something like:
firstMethod();
startTimer();
secondMethod();
I have tried using a Timer but it does not work
You can't just start a Timer and do nothing. When the timer fires you need to invoke the secondMethod(...) in the actionPerformed of the Timer.
Use Swing Timer instead of Java Timer and Thread.sleep.
Please have a look at How to Use Swing Timers
Timer timer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
secondMethod();
}
});
timer.setRepeats(false);
timer.start()
A timer won't just stop code execution like sleep does.
You have to assign an ActionListener to it which will be notified when the time is up.
It goes something like this:
firstMethod();
Timer t = new Timer(5000);
t.setRepeats(false);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
secondMethod();
}
})
t.start();

Issue adding statements to JTextArea with delays in between

In the code below I am running my method which adds text to a JTextArea, then i wait 4 seconds and add more text. However it simply waits four seconds then puts all the text down at once. How can I make it so it adds the first text, waits then adds the second block of text?
public static void configuresettings() {
GUI.add("To Begin, Go to www.opionsxo.com");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
GUI.add("Welcome to Configure Settings!");
}
I figured it out, if anyone is interested in how. Then view the code below...
public static void configuresettings() {
GUI.add("To Begin, Go to www.opionsxo.com");
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
GUI.add("Welcome to Configure Settings!");
}
};
Timer timer = new Timer( 4000, actionListener );
timer.setRepeats(false);
timer.start();
}
You shouldn't use Thread.sleep with swing, or it will block your application. For instance, if you resize your window or move a window in front of your application, it won't repaint as needed, because you stopped it. Instead, you should be using Swing Timers.
Your problem is probably because you should revalidate() your JTextArea before sleep or something, but as said, you should change the implementation of it.
Read more here: http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
Don't do anything within the context of the Event Dispatching Thread that might cause it to stop, like calling Thread.sleep.
Instead, trying using a javax.swing.Timer or SwingWorker
Take a look at:
Concurrency in Swing
Worker Threads and SwingWorker
How to Use Swing Timers
For more details
For example:
java for-loop in GUI TextArea
Displaying contents of String array in Swing component as iterations using Time delay. JAVA
I cant run JTextArea multiple times?

Button doesn't disable when function is called

I'm really lost with this:
In this Case the Button should diasable (btnStart.setEnable(false)) when it got clicked.
after this it should call a function, located in an other class.
Everything works, except that the btnStart doesn't disable on click but after the function ist called.
So this:
#Override
public void actionPerformed(ActionEvent buttonKLick) {
if(buttonKLick.getSource() == this.btnStart){
btnStart.setEnabled(false);
try {
Funktionen.fileFinder(Pfad); //The Function
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
Will call the function FileFinder and then disable the button although the button should be disabled before.
You've likely got a threading issue where your other method is taking time and locking up the Swing event thread, preventing Swing from properly painting the button as disabled. What happens if you use a background thread?
i.e.,
if(buttonKLick.getSource() == this.btnStart){
btnStart.setEnabled(false);
new Thread(new Runnable() {
public void run() {
try {
Funktionen.fileFinder(Pfad); //The Function
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}).start();
}
Edit:
Please be sure to read: Lesson: Concurrency in Swing.
No, it will disable the button right when you call setEnabled( false ). Just try calling isEnabled() before you call that function.
What you observe is that the button is only painted in disabled state after the function is executed. That is because your function occupies the one and only thread used to update the UI (the Event Dispatch Thread).
Solution: execute your function on a worker thread, for example using a SwingWorker. Also, read the Swing concurrency guide. This explains in more detail what I mentioned here

JLabel doesn't change back color

Part of my function looks like this
jLabel2.setBackground(Color.YELLOW);
jLabel2.setText("Status : Idle");
boolean ok=cpu21.RestartSSH();
if(ok){
jLabel2.setBackground(Color.GREEN);
jLabel2.setText("Status : Run");
}
Before I enter in function label is Green and Run, but when I come in function it doesn't chabge color to Yellow ( function RestartSSH is executing 5-6 sec, but during that time labels doesn't change colors and captures ). Where I make mistake in painting ?
Make your JLabel opaque so you can set its background colour.
Perform RestartSSH in a separate thread, or your GUI won't respond to events.
Example:
final JLabel jLabel2 = new JLabel("HELLO");
jLabel2.setOpaque(true);
jLabel2.setBackground(Color.YELLOW);
jLabel2.setText("Status : Idle");
//perform SSH in a separate thread
Thread sshThread = new Thread(){
public void run(){
boolean ok=cpu21.RestartSSH();
if(ok){
//update the GUI in the event dispatch thread
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jLabel2.setBackground(Color.GREEN);
jLabel2.setText("Status : Run");
}
});
}
}
};
sshThread.start();
(Update: added call to SwingUtilities.invokeLater)
JLabels is opaque by default, so their's background isn't painted by default. Try with:
jLabel2.setOpaque(true);
or maybe you have to call repaint after changing the color:
jLabel2.repaint();
I suspect that your restartSSH() method is blocking the event dispatch thread. One approach is to use a SwingWorker, as suggested in this example. This would allow you to show the progress of the restart process and set the label appropriately when done.

List in JScrollPane painting outside the viewport

I have a list, each item of which has several things in it, including a JProgressBar which can be updated a lot. Each time one of the items updates its JProgressBar, the ListDataListener on the list tries to scroll it to the visible range using
/*
* This makes the updating content item automatically scroll
* into view if it is off the viewport.
*/
public void contentsChanged(final ListDataEvent evt) {
if (!EventQueue.isDispatchThread()) {
/**
* Make sure the scrolling happens in the graphics "dispatch" thread.
*/
EventQueue.invokeLater(new Runnable() {
public void run() {
contentsChanged(evt);
}
});
}
if (playbackInProgress) {
int index = evt.getIndex0();
currentContentList.ensureIndexIsVisible(index);
}
}
Note that I'm trying to make sure the scrolling is done in the dispatch thread, since I thought maybe the problem was it being scrolled while it was repainting. And yet, I still have a problem where if things are really active, some of the list items paint outside of the viewport, overwriting what's outside the JScrollPane. Forcing an exposure event will repaint those things, but it's annoying.
Is there anything else I need to look out for to stop these things painting outside of their clipping area?
Have you tried explicitly enabling double-buffering on the JList and/or the components that it is drawing over? (with:setDoubleBuffered(boolean aFlag))
Another thought is that you might need to exit the function immediately after delegating to the EDT. The way your code is written, it looks like the update will happen in both threads if ContentChanged is invoked from a non-EDT thread. Logging in the first if (or set a breakpoint in the if -- but not in the runnable -- should help determine if that is your problem.
eg:
public void contentsChanged(final ListDataEvent evt)
{
if (!EventQueue.isDispatchThread())
{
log.debug("Delegating contentsChanged(...) to EDT");
EventQueue.invokeLater(new Runnable()
{
public void run()
{
contentsChanged(evt);
}
});
// don't run ensureIndexIsVisible twice:
return;
}
if (playbackInProgress)
{
int index = evt.getIndex0();
currentContentList.ensureIndexIsVisible(index);
}
}

Categories

Resources