Reputation: 271
I've written the following code
import java.awt.BorderLayout;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
final public class Test
{
JFrame frame;
DrawPanel drawPanel;
boolean up = false;
boolean down = true;
boolean left = false;
boolean right = true;
private int timeStep = 0;
private int ballYTravel = 100;
private int BALL_NUM = 24;
public static void main(String... args)
{
new Test().go();
}
private void go()
{
frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawPanel = new DrawPanel();
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.setResizable(false);
frame.setSize(800, 600);
frame.setLocationByPlatform(true);
frame.setVisible(true);
moveIt();
}
class DrawPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public double getY(int i, int t) {
return 200 + ballYTravel / 2 * (Math.sin(timeStep * (i / 200 + 0.08)));
}
public void paintComponent(Graphics g)
{
for (int k = 0; k < BALL_NUM; k++ ) {
g.fillRect(100 + 20 *k , (int) getY(k, timeStep), 6, 6);
}
timeStep++;
}
}
private void moveIt()
{
while (true)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
e.printStackTrace();
}
frame.repaint();
}
}
}
It runs and animates, however it is not animating in the same fashion as the Javascript code I referenced it from which can be found here http://codepen.io/anon/pen/ZYQoQZ
any help in understanding why is appreciated
Upvotes: 1
Views: 97
Reputation: 205775
Your transliteration reveals several problems:
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
Don't use setSize()
when you really mean to override getPreferredSize()
.
Invoke pack()
to let the container adopt its preferred size.
Use javax.swing.Timer
to pace the animation.
Revised code, incorporating @Mad's fix and using drawOval()
:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
final public class Test {
JFrame frame;
DrawPanel drawPanel;
private int timeStep = 0;
private int ballYTravel = 100;
private int BALL_NUM = 24;
public static void main(String... args) {
new Test().go();
}
private void go() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawPanel = new DrawPanel();
frame.add(BorderLayout.CENTER, drawPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
Timer t = new Timer(10, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
drawPanel.repaint();
}
});
t.start();
}
});
}
private class DrawPanel extends JPanel {
public double getY(int i, int t) {
return 200 + ballYTravel / 2 * (Math.sin(t * (i / 200d + 0.08)));
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int k = 0; k < BALL_NUM; k++) {
g.drawOval(100 + 20 * k, (int) getY(k, timeStep), 8, 8);
}
timeStep++;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(700, 500);
}
}
}
Upvotes: 5
Reputation: 347184
There are (possibly) two basic problems...
getY
, you are ignoring the parameter t
and using timeStep
instead, while, technically, this probably isn't going to make a MASSIVE difference, it is an area of concerni/200
will result in int
result, where you really want a double
. Change it to i/200d
For example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
final public class Test {
private int timeStep = 0;
private final int ballYTravel = 100;
private final int BALL_NUM = 24;
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 DrawPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
class DrawPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawPanel() {
new Timer(10, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
timeStep++;
repaint();
}
}).start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
public double getY(int i, int t) {
return 100 + ballYTravel / 2 * (Math.sin(t * (i / 200d + 0.08)));
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int k = 0; k < BALL_NUM; k++) {
g.fillRect(10 + 20 * k, (int) getY(k, timeStep), 6, 6);
}
}
}
}
You're also breaking the paint chain, which is going to cause you issues in the long run, make sure you are calling super.paintComponent
...
For more details see...
Upvotes: 5