I have one three rectangles in my canvas. I wanted to change the colours of three rectangles
in a slow manner one by one.
For example: When starting the application, user should be able to see three rectangles with the same colour (blue).
After 2 secons that rectangles colour should change to red.
Again after 2 secons the next rectangles colour should get changed.
The last one is also done the same way, that means after 2 seconds of the 2nd rectangle.
I wrote in my own way. But it is not working. All the rectanlges are changed together. I want one by one.
Could anyone give me the logic.
final Runnable timer = new Runnable() {
public void run() {
//list of rectangles size =3; each contain Rectangle.
for(int i = 0 ; i < rectangleList.size();i++){
if(rectangleListt.get(i).getBackgroundColor().equals(ColorConstants.blue)){
try {
rectangleList.get(i).setBackgroundColor(ColorConstants.yellow);
Thread.sleep(1500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//rectSubFigureList.get(i).setBorder(null);
}/*else{
rectSubFigureList.get(i).setBackgroundColor(ColorConstants.blue);
}*/
}
You're likely calling Thread.sleep inside of Swing's event thread or EDT (for event dispatch thread), and this will cause the thread itself to sleep. Since this thread is responsible for all of Swing's graphics and user interactions, this will in effect put your entire application to sleep, and is not what you want to have happen. Instead, read up on and use a Swing Timer for this.
References:
Swing Timer tutorial
Swing Event Dispatch Thread and Swingworker tutorial
To expand on Hidde's code, you could do:
// the timer:
Timer t = new Timer(2000, new ActionListener() {
private int changed = 0; // better to keep this private and in the class
#Override
public void actionPerformed(ActionEvent e) {
if (changed < rectangleList.size()) {
rectangleList.setBackgroundColor(someColor);
} else {
((Timer) e.getSource()).stop();
}
changed++;
}
});
t.start();
You can set a Timer:
// declaration:
static int changed = 0;
// the timer:
Timer t = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Change the colour here:
if (changed == 0) {
// change the first one
} else if (changed == 1) {
// change the second one
} else if (changed == 2) {
// change the last one
} else {
((Timer) e.getSource()).stop();
}
changed ++;
}
});
t.start();
Related
I have a Timer that shows an animation on the screen when a game event takes place. What I want to do is have the main execution pause until this animation finishes, but everything I try seems to block the Timer from running. I've tried using Thread.sleep() and calling wait() and notify() on a lock object, but with the same result. The Timer listener's actionPerformed() is never called.
This code sets up the timer:
protected void showMovingEffect(int steps, Direction dir, AnimatedImageSet imgs) {
effectsPane.runAnimation(imgs, dir, steps);
waiting = true;
while (waiting) {
synchronized(animationWaitLock) {
try {
animationWaitLock.wait();
} catch (InterruptedException e) {}
}
}
}
And the Timer and listener inside the EffectsPane object:
private void runAnimation(AnimatedImageSet ais, Direction dir, int iters) {
System.out.println("run");
imgs = ais;
top = 0;
left = 0;
topStep = dir.getRowIncrement() * 10;
leftStep = dir.getColIncrement() * 10;
iterations = iters;
index = 0;
active = true;
timer.start();
}
public void actionPerformed(ActionEvent e) {
System.out.println(index);
top += topStep;
left += leftStep;
index++;
currentImage = imgs.getImage(index);
repaint();
if (index == iterations) {
active = false;
timer.stop();
synchronized(animationWaitLock) {
animationWaitLock.notify();
}
waiting = false;
}
}
The System.out.println call at the start of the actionPerformed() is never called, so either the wait() call is also pausing the Timer, or something is blocking it. If I comment out the sleep/wait lines in showMovingEffect(), the animation runs, but the program does not pause.
One approach would be to display a modal dialog while the animation proceeds. As discussed here, user interaction will be foreclosed, but background GUI updates in response to the javax.swing.Timer will continue. You can allow the user to dismiss the dialog at any time, as shown here, but you may want to abandon the animation at that point.
no input from the user is needed.
You can block user interaction without displaying a dialog by entering a SecondaryLoop after the animation starts.
SecondaryLoop loop = Toolkit.getDefaultToolkit()
.getSystemEventQueue().createSecondaryLoop();
timer.start();
loop.enter();
When the animation concludes, exit() the SecondaryLoop:
public void actionPerformed(ActionEvent e) {
…
if (index == iterations) {
timer.stop();
loop.exit ();
…
}
}
You can try this:
timer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// your code
}
});
I have a JFrame with two buttons. One of the buttons when clicked moves (btnMove) the other button(shape) from the present position to another.I am using a thread as a timer to count in seconds but each time the counter increments, the button moves back to its original position.
public class FrameTh extends JFrame {
class count extends Thread {
public int p = 0;
public void run() {
for (int i = 1; i < 100; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e);
}
lblCounter.setText("Seconds: " + i);
}
}
}
count t1 = new count();
private void formWindowActivated(java.awt.event.WindowEvent evt) {
t1.start();
}
private void btnMoveActionPerformed(java.awt.event.ActionEvent evt) {
shape.setLocation(23, 44);
}
The core problem is you're fighting the layout management API, which when you call setText is causing the container to be invalidated and relayed out
You might consider using something like JLayeredPane, but remember, you become entirely responsible for the size and position of the component
The other problem you have is you're violating the single threaded nature of Swing, Swing is not thread safe, meaning you shouldn't update the ui from out of the Event Dispatching Thread.
To solve that particular problem you should use a Swing Timer instead of a thread, see How to use Swing Timers for more details
I decided to make something fun as a break from reading programming books, and I have hit a snag. This is my first swing program, and am ready to wrap it up!
The problem: I clearly don't understand how threads work with Swing. I am writing a GUI for a black jack game, and I did all of the functionality first e.g. drawing a new card to the screen when the player hits, showing the dealer hit after the player decides to stay, etc. This all works.
When I added in the logic to check for a user bust when hitting, or who wins when the user decides to stay, the game instantly goes to the win/loss screen before drawing either: the card the user got that caused a bust, or; the cards that the dealer drew when hitting (if any).
I tried inserting Thread.sleep in various places, to no avail. The program would sleep before drawing the card, then end instantly as above (even though it was placed logically after the call to draw, and before the call to calculate a winner).
also I tried to follow the MVC paradigm here, just fyi.
P.S. my program runs on one thread, I do not explicitly instantiate another, but I vaguely remember reading that Swing spawns it's own thread for graphics stuff
Sorry for that long intro! Here is some code:
The Model class' pertinent methods
void hit() {
//run when button is clicked
player.hand.add(deck.deck.get(0));
deck.deck.remove(0);
}
boolean isBust() {
if (player.getScore() > 21)
return true;
return false;
}
void dealerHit() {
while (dealer.getScore() < 17) { //could implement soft 17 rules for more difficulty
dealer.hand.add(deck.deck.get(0));
setChanged();
notifyObservers();
deck.deck.remove(0);
//Here was one attempt
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
boolean isWin() {
//and another
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if ((player.getScore() > dealer.getScore() && player.getScore() <= 21) || dealer.getScore() > 21)
return true;
return false;
}
void stay() {
dealerHit();
isWin();
}
View Class
void addHitListener(ActionListener HitListener) {
hit.addActionListener(HitListener);
}
void addStartListener(ActionListener StartListener) {
start.addActionListener(StartListener);
}
void addStayListener(ActionListener StayListener) {
stay.addActionListener(StayListener);
}
void display() {
JFrame myFrame = new JFrame("BlackJack");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setContentPane(this);
myFrame.setPreferredSize(new Dimension(700,550));
myFrame.pack();
myFrame.setVisible(true);
}
void addCards(Player p, Dealer d) {
topPanel.remove(start);
pcardPanel.add(playerlabel);
dcardPanel.add(dealerlabel);
for (Card c : p.hand) {
ImageIcon cc = new ImageIcon(c.img);
JLabel cC = new JLabel(cc);
//cC.setAlignmentX(alignmentX); use to get X alignment of card 1 & 2 for splits
//cC.setAlignmentY(alignmentY); same for Y, then increment by .3f
pcardPanel.add(cC);
}
for (Card c : d.hand)
dcardPanel.add(new JLabel(new ImageIcon(c.img)));
topPanel.add(new JLabel("Options: "));
topPanel.add(hit);
topPanel.add(stay);
validate();
repaint();
}
void endGame(boolean isWin) {
//I think I tried here, too
removeAll();
setBackground(new Color(0, 122, 0));
if (isWin == true)
add(new JLabel("You won!"));
else
add(new JLabel("You Lost"));
validate();
repaint();
}
public void hitPlayer(Player p) {
JLabel hits = new JLabel(new ImageIcon(p.hand.get(p.hand.size()-1).img));
//hits.setAlignmentY(alignmentY);
pcardPanel.add(hits);
validate();
repaint();
}
public void hitDealer(Dealer d) {
dcardPanel.add(new JLabel(new ImageIcon(d.hand.get(d.hand.size()-1).img)));
validate();
repaint();
}
Controller class:
public class Controller implements Observer {
BlackJack game;
Table t;
Controller(BlackJack game, Table t) {
this.game = game;
this.t = t;
this.game.addObserver(this);
this.t.addHitListener(new HitListener());
this.t.addStartListener(new StartListener());
this.t.addStayListener(new StayListener());
}
public void go() {
t.display();
}
public void update(Observable obj, Object observed) {
t.hitDealer(game.getDealer());
}
class HitListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
game.hit();
t.hitPlayer(game.getPlayer());
if (game.isBust() == true)
t.endGame(false);
}
}
class StartListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
t.addCards(game.getPlayer(), game.getDealer());
}
}
class StayListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
game.stay();
//doStay();
if (game.isWin() == true)
t.endGame(true);
else
t.endGame(false);
}
}
I just had a thought, since I'm doing this in the actionPerformed methods, could that be why sleep seemed to affect the GUI thread, and not draw the card(s) then sleep. I bet that is it. But I'm going to eat dinner, hopefully someone smarter than myself can lend a hand! Thanks in advance
P.P.S. if there are any typos (I don't think there are) just know that it all compiles and works! And no warnings, if that helps
Swing is indeed a single-thread library, like most UIs. There are also many optimizations to make it work fast. Case in point - most paintings are cached and displayed together. Even if this was not the case, you'd be relying on the speed of the system, which is not a good idea.
If you want a delayed action, you need to use swing's timer (not to be confused with the other timer class). That class has an action listener that goes off when the timer expires. In your case, you'd detect the win/bust condition, start the timer (e.g to fire in 2 seconds) and continue the drawing as usual.
This is a little too long for me to read and understand... But I guess your problem is because you are processing everything in the Event Dispatching Thread.
When you paint something on the GUI and then have more processing, the paint will actually reflect on the GUI only when the whole of the thread has finished processing. That's why you are not seeing your drawing before your Thread.sleep method.
Instead you should use SwingWorker to split your processing and GUI updating to different threads.
Look at this https://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
I'm trying to make several JRadioButtons blink at the same time with this blink method:
private void blink(JRadioButton button, boolean blinking)
{
if(blinking)
{
while(true)
{
try
{
button.setSelected(true);
Thread.sleep(500);
button.setSelected(false);
Thread.sleep(500);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
else
{
button.setSelected(false);
}
}
I know it has something to do with threads but I'm not that familiar with them.
I'm trying to make several JRadioButtons blink at the same time with this blink method
IMHO you don't need multiple while loops.
Just add all buttons you want to blink to an ArrayList, then in the same while loop, loop over that list and blink the buttons. So, instead of
button.setSelected(true);
Thread.sleep(500);
button.setSelected(false);
Thread.sleep(500);
You can use
for(int i=0; i<yourList.size(); i++) {
yourList.get(i).setSelected(true);
}
Thread.sleep(500);
for(int i=0; i<yourList.size(); i++) {
yourList.get(i).setSelected(false);
}
Thread.sleep(500);
But this is a bad practice. Use the Timer class and schedule a thread to execute every 500ms instead:
Timer t = new Timer(500, new ActionListener() {
boolean selected = false;
#Override
public void actionPerformed(ActionEvent e) {
selected = !selected;
for(int i=0; i<yourList.size(); i++) {
yourList.get(i).setSelected(selected);
}
}
});
t.start();
You can't animate the GUI by using Thread.sleep. In fact, you must never call Thread.sleep on the Event Dispatch Thread because that very thread is in charge of repainting the GUI, which it will clearly not be able to do while sleeping.
What you must use is the Swing Timer class and schedule it to repeat at the desired interval.
I've got a working Java program and I would like to draw an object on the display every X seconds. What is the best way to do this? I was thinking of using a for loop and some sleep statements, but I'm curious if there is an easier or more efficient way to go about this.
Thanks.
The simplest way would be to use a javax.swing.Timer
Timer timer = new Timer(X, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Update the variables you need...
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
You might also like to have a read through
The Event Dispatching Thread
Concurrency in Swing
So you can understand why you should never use a while (true) { Thread.sleep(X) } call in Swing (inside the EDT)
ScheduledExecutorService might help here. The Javadoc shows example usage. Don't forget to call the shutdown method when you're finished.
Using Thread, this will draw a rectangle on the screen every XMilSeconds. This will stop after 5 runs. Edit the xMilSeconds for slower runs, and j > 4 for how many runs before stoping. It does freeze though, that I can't fix.
int i = 0;
private long xMilSeconds = 300;
private boolean paint;
public boolean running = true;
public void paint(Graphics g)
{
super.paint(g);
if(paint)
{
for(;i < i+1;)
{
g.drawRect(i+49,i+49,i+299,i+99);
g.setColor(Color.RED);
g.fillRect(i+49,i+49,i+299,i+99);
}
paint = false;
}
}
public void run()
{
while(running)
{
try
{
Thread.sleep(xSeconds);
paint = true;
repaint();
i++;
j++;
if(j > 4)
{
running = false;
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}