So I'm writing a program that plays Reversi/Othello against a player. I wrote a method to make a short animation of the pieces flipping-
public void flip(int row, int col, Graphics window)
{
Color a;
if (pieces[row][col]==1)
a = Color.black;
else
a = Color.white;
for ( int size = 90; size>0; size-=2)
{
try { Thread.sleep(11,1111); } catch (InterruptedException exc){}
window.setColor(new Color( 0, 100, 0 ));
window.fillRect(row*100+3, col*100+3, 94, 94);
window.setColor(a);
window.fillOval(row*100 + 5, col*100+5+(90-size)/2, 90, size);
}
if (a==Color.black)
a=Color.white;
else
a=Color.black;
for ( int size = 0; size<90; size+=2)
{
try { Thread.sleep(11,1111); } catch (InterruptedException exc){}
window.setColor(new Color( 0, 100, 0 ));
window.fillRect(row*100+3, col*100+3, 94, 94);
window.setColor(a);
window.fillOval(row*100 + 5, col*100+5+(90-size)/2, 90, size);
}
}
It works well and looks great, but the problem is that since thread.sleep pauses the entire program, it can only flip one piece at a time. Is there something I can do to pause just that method without interrupting the rest of the program?
Thanks everyone. The new thread worked, but now I have a different problem. The three setcolor methods in the flip method are getting mixed up. I think it's because some threads are setting the color to green, some to black and some to white. How do I fix this?
You should make run this method inside a dedicated thread created from your main program.
You should run flip in separate Thread in that case. The simplest example:
Thread t = new Thread(new Runnable() {
public void run() {
flip();
}
});
t.start();
What you are targetting is asynchronous programming: schedule a javax.swing.Timer that, each time it fires, does one animation step. This would be the idiomatic way for a GUI program; the approach with a separate thread that sleeps in a loop and uses invokeLater in each step will also work, but is less elegant because it uses more system resources (another thread that mostly just sleeps).
You need to create a separate thread that will handle the animation. That thread can call Thread#sleep, since Thread#sleep does not pause "the entire program", but only the current thread. At each step in the animation, it should change some state indicating the current stage of the piece flip animation and then request a repaint.
Related
I want to make a ProgressBar move gradually using a Jbutton. To achieve this I am using a for loop and the method Thread.sleep. The problem is that insted of moving a tiny bit every second (the progress bar) after pressing the button, the program waits until the loop finishes and then does instantly move the progress up. When I take the loop outside of the button listener it works as I want but I really need it to work when pressing the button. Here is the code:
progressBar.setOrientation(SwingConstants.VERTICAL);
progressBar.setMinimum(0);
progressBar.setMaximum(100);
progressBar.setValue(50);
panel1.setLayout(null);
panel1.add(progressBar);
progressBar.setBounds(40,6,100,100);
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int counter = 5;
for (int i = 0; i < 5; i++) {
progressBar.setValue(progressBar.getValue() + counter);
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
});
If anyone can help me I will be very grateful!
Your code runs on the Event Dispatcher Thread (EDT). That thread is responsible for handling events, but also for repainting. Because it's just one thread, the repainting only occurs after your method ends.
There are some ways to solve this. In your case, a javax.swing.Timer would probably be easiest. Instead of running the loop in a single method, the button click starts a timer that runs every second. When it's done the timer can cancel itself. A slightly more difficult alternative is to use a SwingWorker. You could publish data in the doInBackGround method, and override process to perform the updates to the progress bar.
For more information, please read Concurrency in Swing.
I'm working on a processing sketch here: https://github.com/davidcool/processing/tree/master/polyhedrons/polyhedrons_4
It's not very elegant code-wise but works fine. It renders rotating complex (meaning many faces) polyhedrons to the screen. Each time you click it adds 5 new rotating polyhedron objects... Once you have 20-25 objects it starts to bog down, meaning the frames/sec drop and it looks jumpy.
I've been reading about threading in Processing/Java. So I started to think maybe I could split the total number of objects out to each processing core. I saw this example in particular: http://www.camnewnham.com/threading-in-processing/
Before I dive into this goose chase, does anyone know if threading would help in terms of animation speed? When I run a sketch normally does it always just use one core for the draw loop? Can threading spread out the object animation rendering over "idle" cores?
Thanks!
The draw() function is always called by the same Thread. This same Thread also calls the mousePressed() and similar functions. In Processing this is called the Animation Thread- Java has a similar idea, called the EDT.
So you can't simply move your drawing to other threads. This will cause problems with the rendering- for example, the Animation Thread might be trying to draw the next frame, while your drawing threads are still trying to draw the previous frame. It's not going to work.
You could try to do your own multi-threaded off-screen buffering by having all your helper threads draw to a PGraphics instead of calling the Processing drawing methods directly. You'd then have to synchronize all of your drawing threads and only draw your PGraphics to the screen (using the Animation Thread) after all of those threads have finished.
This is not a particularly difficult job, but it does involve a pretty decent understanding of how threading works, which goes beyond the scope of most Processing sketches.
Also note that JavaScript doesn't have multiple threads, so anything you do with threading will not work in JavaScript mode.
Here's an example sketch that uses just the Animation Thread to draw 10000 random points every frame. I get about 7 FPS with it:
PGraphics sharedGraphics;
void setup(){
size(500, 500);
sharedGraphics = createGraphics(500, 500);
}
void draw(){
sharedGraphics.beginDraw();
sharedGraphics.background(0);
for(int i = 0; i < 10000; i++){
sharedGraphics.ellipse(random(500), random(500), 5, 5);
}
sharedGraphics.endDraw();
image(sharedGraphics, 0, 0);
println(frameRate);
}
And here is how you might use multiple Threads to render to a PGraphics:
PGraphics sharedGraphics;
void setup() {
size(500, 500);
sharedGraphics = createGraphics(500, 500);
}
void draw() {
ArrayList<Thread> threads = new ArrayList<Thread>();
sharedGraphics.beginDraw();
sharedGraphics.background(0);
for (int i = 0; i < 100; i++) {
Thread t = new DrawThread();
threads.add(t);
t.start();
}
for (Thread t : threads) {
try {
t.join();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
sharedGraphics.endDraw();
image(sharedGraphics, 0, 0);
println(frameRate);
}
class DrawThread extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
sharedGraphics.ellipse(random(500), random(500), 5, 5);
}
}
}
However, the performance of that is even worse than the single-threaded model, and I get strange artifacts (some of the ellipses are filled, others are not) which suggests that PGraphics is not thread-safe. That might depend on the type of renderer you're using. You might then add some synchronization:
class DrawThread extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
synchronized(sharedGraphics) {
sharedGraphics.ellipse(random(500), random(500), 5, 5);
}
}
}
}
That works, but the performance of it is even worse, since you're still only accessing the PGraphics with one thread at a time, and you're doing a bunch of extra work every time draw() is called.
You might be able to fiddle around with it to make it work, but the end result is that it's probably not worth it.
"Some people, when confronted with a problem, think “I know, I'll use multithreading”. Nothhw tpe yawrve o oblems."
I'm attempting to get an animation working in a game I'm developing. The animation works by setting a button size to very small, then gradually growing it to its normal size again. I have it working, except I'm having timing issues.
Sometimes the button will grow almost instantly, sometimes it goes VERY slow. I'm looking for something inbetween, and I need it to ALWAYS grow at that size, not some times fast sometimes slow.
I've looked into it and I found this pseudocode:
distance_for_dt = speed * delta_time
new_position = old_position + distance_for_dt
Unfortunately I don't understand what's being said, and I don't know how to apply this to my code. Can anyone help with that or explain what's being said in the above pseudocode?
Here's my timer code, timer is already defined above as a Timer, and z[] is just a pair of coordinates:
timer = new Timer(18, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Dimension dim = button[z[0]][z[1]].getSize();
if (dim.getHeight() < 79.9) {
button[z[0]][z[1]].setSize((int) (dim.getWidth() + 6), (int) (dim.getHeight() + 6));
} else {
button[z[0]][z[1]].setSize(80, 80);
timer.stop();
}
}
});
timer.start();
Depending on how many updates you're calling on your Swing application, it may be getting "backed up" and slowing down. For instance, if you wanted to accomplish the animation without a Timer, you could just do something like this:
// example method to do animation
public void animateButton(final int wait){
Thread thread = new Thread(){
public void run(){
// some loop structure to define how long to run animation
Dimension dim = button[z[0]][z[1]].getSize();
while (dim.getHeight() < 79.9){
SwingUtilities.invokeLater(new Runnable(){
//update Swing components here
});
try{ Thread.Sleep(wait); }
catch(Exception e){}
}
}
}
}
thread.start();
}
I think this may be similar to how a Timer updates the GUI, as Timers run on a separate thread. I would look into whether or not you need to use invokeLater(new Runnable) inside a timer to properly schedule the task. I had to do this to allow a project I was working on to keep responsive during long tasks. If you really needed to ensure the speed and maybe DROP updates to adjust for system lag, then you'll need to be calculating how complete the animation is vs how much time has passed, using a method call such as System.currentTimeMillis() or System.nanoTime(). Then, adjust accordingly for each step of the animation.
Okay I posted a question a while back regarding how to get a method to pause without pausing the whole program. Here's the link for context- How do I make method pause without pausing the whole program?. The answer I got was to create a new thread and pause it from there.
The new thread worked, but now I have a different problem. Since I'm running flip 5-6 times simultaneously the three setcolor methods, which all use the same Graphics, are getting mixed up. I think it's because some threads are setting the color to green, some to black and some to white. The result is that the pieces rapidly change color during their animation. How do I fix this?
public void flip(int row, int col, Graphics window)
{
Color a;
Color b = new Color(0, 100, 0);
if (pieces[row][col]==2)
a = Color.black;
else
a = Color.white;
for ( int size = 90; size>=0; size-=2)
{
try { Thread.sleep(5,5555); } catch (InterruptedException exc){}
window.setColor(b);
window.fillRect(row*100+3, col*100+3, 94, 94);
window.setColor(a);
window.fillOval(row*100 + 5, col*100+5+(90-size)/2, 90, size);
}
if (a==Color.black)
a=Color.white;
else
a=Color.black;
for ( int size = 0; size<=90; size+=2)
{
try { Thread.sleep(5,5555); } catch (InterruptedException exc){}
window.setColor(b);
window.fillRect(row*100+3, col*100+3, 94, 94);
window.setColor(a);
window.fillOval(row*100 + 5, col*100+5+(90-size)/2, 90, size);
}
}
Since you are now using Threads which all change the same value, you need to learn about synchronization.
This jSlider code causes the application to hang.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
try {
for(int i=0;i<100;i++)
{
jSlider1.setValue(i);
Thread.sleep(3000);
}
} catch (InterruptedException ex) {
Logger.getLogger(AsdView.class.getName()).log(Level.SEVERE, null, ex);
}
}
thank you guys i am updating the answer
Timer time = new Timer(100, new ActionListener() {
int percent = 0;
#Override
public void actionPerformed(ActionEvent e) {
percent++;
if (percent>100)
percent = 0;
jSlider1.setValue((int)(100*(percent/600.0)));
}
});
time.start();
I am guessing you are trying to do some kind of smooth scroll.
That code freezes because the event thread that handles the window painting, sizing, etc..., is being frozen by you executing Thread.sleep(3000), 100 times.
I would recommend that you use a Swing timer that changes the scroll bar little by little.
i don't know why you put the sleep for 3 secs and that too in for loop of 100
3*100 = 5 mins so it will hang upto 5 mins
remove Thread.sleep(3000);
it will work fine and won't hang
When you say your application 'hangs', that generally means that you have some sort of deadlock that prevents your threads from making progress. Is that what you're observing in your program? The way it's currently written, the current thread of execution will take at least 300 seconds to complete. Is this work being done on the main thread of execution? If so, you may want to consider creating a new Thread to do this work.