Reputation: 3
I have a situation where I'm moving a ball. However, after struggling with the queue that repaint() places paintComponent(Graphics g) in. I resorted to using paintImmediately. The problem now is that without access to super.paintComponent(g), I don't know how to clear the canvas each time before I paint. So one possible answer to my question would be a way to clear the canvas by itself. I also found that Threads could be a possible solution but after a great many attempts to implement that idea, I still don't understand that so if someone could show correct implementation for that I would be very grateful.
Here is my code:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JButton;
public class PhysicsEngine extends JPanel {
double x, y;
JPanel pan;
JButton b1;
JButton b2;
JButton b3;
JButton b4;
JButton b5;
public static void main(String[] args) {
JFrame frame = new JFrame("Ball Engine");
PhysicsEngine gui = new PhysicsEngine();
frame.add(gui, BorderLayout.CENTER);
frame.setSize(600, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public PhysicsEngine() {
b1 = new JButton("1");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
startFirst();
} catch (InterruptedException exception) {
}
}
});
this.add(b1);
b2 = new JButton("2");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startSecond();
} catch (InterruptedException exception) {
}
}
});
this.add(b2);
b3 = new JButton("3");
b3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startThird();
} catch (InterruptedException exception) {
}
}
});
this.add(b3);
b4 = new JButton("4");
b4.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startFourth();
} catch (InterruptedException exception) {
}
}
});
this.add(b4);
b5 = new JButton("5");
b5.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startFifth();
} catch (InterruptedException exception) {
}
}
});
this.add(b5);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("" + y);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
g2d.fillOval((int) x, (int) y, 30, 30);
}
public void startFirst() throws InterruptedException {
x = 300;
y = 80;
// xPos= 0*t*t + 0*t + 300 this is constant at 300
for(int t = 1; t<70;t++){
y = .1 * t * t + 0 * t + 80; // parametric equation for y
repaint();
paintImmediately((int)x, (int)y, 30, 30);
Thread.sleep(10);
}
}
public void startSecond() throws InterruptedException {
x = 300;
y = 550;
for (int t = 1;t<150; t++) {
// xPos= 0*t*t + 0*t + 300 this is constant at 300
y = .1 * t * t - 15 * t + 550; // parametric equation for y
repaint();
paintImmediately((int)x, (int)y, 30, 30);
Thread.sleep(10);
}
}
public void startThird() throws InterruptedException {
y = 550;
x = 50;
for (int t = 1;t<150; t++) {
y = .1 * t * t - 15 * t + 550; // parametric equation for y
x = 0 * t * t + 3 * t + 50; // parametric equation for x
repaint();
paintImmediately((int)x, (int)y, 30, 30);
Thread.sleep(10);
}
}
public void startFourth() throws InterruptedException {
y = 50;
x = -4;
for (int t = 1;t<110; t++) {
// xPos= 0*t*t + 0*t + 300 this is constant at 300
y = .001*t * t * t + 50; // given parametric equation for y
x = t - 4; // given parametric equation for x
repaint();
paintImmediately((int)x, (int)y, 30, 30);
Thread.sleep(10);
}
}
public void startFifth() throws InterruptedException {
for (int t = 1; t < 130 /* goes for 1.5 seconds */; t++) {
y = 200 * Math.sin(.05*t) + 300; // given parametric equation for y
x = 200 * Math.cos(.05*t) + 300; // given parametric equation for x
repaint();
paintImmediately((int)x, (int)y, 30, 30);
Thread.sleep(10);
}
}
}
Upvotes: 0
Views: 347
Reputation: 347332
Your problem isn't the "paint queue", it's the fact that you're violating the single threaded nature of the API, by calling Thread.sleep
within the context of the EDT.
Instead of using for-loop
s with Thread.sleep
in them, you should make use of a Swing Timer
which updates the state of the variables paintComponent
relies on (and call repaint
)
Swing Timer
can be thought of a pseudo loop, whose ActionListener
is called within the context of the EDT, making it safe to update the UI from
Start by having a look at Concurrency in Swing and How to Use Swing Timers for more details
As a conceptual example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private PhysicsPane physicsPane;
public TestPane() {
physicsPane = new PhysicsPane();
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
JButton b1 = new JButton("1");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
startFirst();
}
});
this.add(b1, gbc);
this.add(physicsPane, gbc);
}
protected void startFirst() {
physicsPane.startFirst();
}
}
public class PhysicsPane extends JPanel {
private Timer timer;
private double xPos, yPos;
private int tick;
public PhysicsPane() {
setBackground(Color.BLUE);
}
protected void stopTimer() {
if (timer == null) {
return;
}
timer.stop();
timer = null;
}
public void startFirst() {
stopTimer();
xPos = 300;
yPos = 500;
tick = 0;
timer = new Timer(10, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (tick >= 150) {
stopTimer();
return;
}
yPos = .1 * tick * tick - 15 * tick + 550;
tick++;
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.fillOval((int) xPos, (int) yPos, 30, 30);
g2d.dispose();
}
}
}
Upvotes: 1