I have a simple program that draws the trajectory of a particle launched from the origin at a certain speed and angle. I created a subclass of JPanel to handle the drawing of this. My everytime my subclass is redrawn it takes the difference between the current time and the initial time(both in milliseconds), converts this to seconds, then finds the x and y coordinate of where the particle should be at that point in time, and finally takes those x and y coordinates and draws them on the screen. My problem is that my subclass seems to be redrawn at interval that seem long because there are only a few dots that are shown.
My drawing method:
private void doDrawing(Graphics g) {
Dimension size = getSize();
Insets insets = getInsets();
int w = size.width - insets.left - insets.right;
int h = size.height - insets.top - insets.bottom;
Graphics2D g2d = (Graphics2D) g;
g.drawString("Acceleration: -9.8m/s i", 0, 20);
StringBuilder b = new StringBuilder();
b.append("Current Velocity: ");
b.append(String.valueOf(sim.getVector(tickSpeed
* ((System.currentTimeMillis() - initTime) / 1000)).getMagnitude()));
b.append(" m/s at ");
b.append(String.valueOf(sim.getVector(tickSpeed
* ((System.currentTimeMillis() - initTime) / 1000)).getDirection().getDirectionDeg()));
b.append(" degrees");
g.drawString(b.toString(), 0, 30);
drawPreviousPoints(g2d);
drawCurrentPointAndAppend(g2d, w, h);
repaint();
}
private void drawCurrentPointAndAppend(Graphics2D g2d, int w, int h) {
g2d.setColor(Color.red);
double height = (length / w) * h;
Vector2D c = sim.getVector(tickSpeed
* ((System.currentTimeMillis() - initTime) / 1000));
double currentX = w
* ((sim.getX(tickSpeed
* ((System.currentTimeMillis() - initTime) / 1000))) / length);
double currentY = h
* (1 - ((sim.getY(tickSpeed
* ((System.currentTimeMillis() - initTime) / 1000))) / height));
g2d.drawLine((int) currentX, (int) currentY, (int) currentX,
(int) currentY);
g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_MITER));
g2d.drawLine((int) currentX, (int) (currentY),
(int) (currentX + w * (c.getX() / length)),
(int) (currentY + (h * -(c.getY() / height))));
xList.add(currentX);
yList.add(currentY);
}
private void drawPreviousPoints(Graphics2D g2d) {
g2d.setColor(Color.blue);
g2d.setStroke(new BasicStroke(7, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND));
if (!xList.isEmpty()) {
for (int i = 0; i < xList.size(); i++) {
g2d.drawLine(xList.get(i).intValue(), yList.get(i).intValue(),
xList.get(i).intValue(), yList.get(i).intValue());
}
}
}
tickSpeed is just a variable that I use to speed up or slow down the particle. It runs fine; however, the animation seems very choppy.
An important rule of Swing- You don't control the paint process...
Don't perform these calculations within the paintComponent
. The paintComponent
is meant to paint the current state of the UI and may be called at any time for many reasons, most of which are outside your control.
Instead, consider using a javax.swing.Timer
set to repeat at a regular interval (40ms is 25 ticks a second).
Set up a model which keeps track of the particles current been processed. When the timer ticks, calculate your particle positions and update them, then call repaint
.
Within your paintComponent
, simply paint the current state of your model.
Have a look at Concurrency in Swing and How to use Swing Timers for more details