I have a very basic JPanel
that is set inside its own JFrame
.
The JPanel implements actionlistener
and overrides paintcomponent
.
I have a bunch of stuff drawn in the paintcomponent method, just shapes and polygons, most is fixed but theres 2 components that rotate. This is done by a timer.
The timer is a Swing Timer
;
By fixed I mean theres no variables that can affect its location.
The class has a StartTimer (StartTheCountdown())
method that starts a timer. On each timer tick the action that is performed is that it increments an angle by a fixed number and then it calls for the window to be repainted.
This is to rotate the couple of components that are not fixed. (which I have left in the code for you to see)
The problem im having is that if you resize the window it causes the timer to lag and thus the rotation doesn't happen in the right amount of time. When you stop resizing its goes back to normal.
If you just do a quick single drag and resize its not noticeable, however just for testing if I click and hold and drag furiously all over the screen for some seconds when I let go its noticeably lagged, almost as if its come to a halt and only continues when I let go.
I've read about using different threads for drawing and performing certain tasks, SwingWorker? But I'm not too sure how to use it in my case.
Any tips on how to prevent this lag?
EDIT: I have added new code that is ready to compile and run AS IS.
If you leave it to run the arrow stops at the bottom after 30 seconds. If you resize the window continuously for a second or so, the timer lags so after 30 seconds it hasnt reached the bottom yet. This lag while resizing is what im trying to prevent.
import java.awt.* ;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
class guidemo{
JFrame clockscreen = new JFrame();
JPanel clockpanel = new JPanel(new GridLayout(1,1));
Theclock clock ;
guidemo ()
{
clock = new Theclock();
clockscreen.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
clockscreen.setTitle( "Countdown" );
clockscreen.setLocation(0,0);
clockscreen.setSize(830,830);
clockscreen.add(clockpanel);
clockpanel.add(clock);
clockscreen.setVisible(true);
clock.StartTheCountdown();
}
public static void main(String[]args)
{
//Setup demo
guidemo demo = new guidemo();
}
}
class Theclock extends JPanel implements ActionListener
{
Timer clockticker = new Timer(40,this);
double theta = 0;
public void StartTheCountdown(){
clockticker.start();
}
public void StopTheCountdown(){
clockticker.stop();
}
public void paintComponent(Graphics gc)
{
super.paintComponent(gc);
Graphics2D g2d = (Graphics2D)gc;
AffineTransform tx = new AffineTransform();
/*
There are lots of other graphics being drawn here
like ovals and rectangles etc but they are not affected
by the incrementing theta. So I removed them.
*/
tx.rotate((double)theta*(3.14/180), 400, 400);
g2d.setTransform(tx);
//Arrow border
g2d.setColor(new Color(159,131,154));
Polygon p = new Polygon();
p.addPoint(350,400);
p.addPoint(400,200);
p.addPoint(450,400);
g2d.fill(p);
}
public void actionPerformed(ActionEvent e)
{
theta += 0.25;
System.out.println(theta);
this.repaint();
if(theta == 180){
StopTheCountdown();
}
}
}
I don't notice any problem using JDK7 on Windows 7. The object continues to rotates as I continuously resize the frame. This may be a version/platform issue.
If it is not repainting then the problem can be that the EDT is lagging and not all events are being generated by the Timer because the default is to use setCoalesce(true), which will combine multiple events into one if the EDT lags.
So you can try using:
timerClock.setCoalesce(false);
If that doesn't work then you can manage the appropriate angle of rotation manually. That is don't just add 0.25 every time the timer fires.
Instead you can keep the timer the Timer started. When the timer fires you get the current time and determine what the appropriate angle should be based on elapsed time since the Timer was started. This way if the EDT get bogged down you will "jump" to the appropriate position when the next Timer event is fired.