0

Ok, so the program's purpose is to just draw and oval and move it across the screen. The code compiles on Eclipse without an error, but when run, no oval is drawn or moved across the screen. I have been researching, and it seems that threads have to do a lot with this, but do I need one for this simple program? I am obviously new to GUI programming with Swing so I would appreciate an explanation or link to one for any additions to the program regarding threads or such related concepts.

public class Game extends JPanel { int x =0; int y =0; private void moveBall() { x+=1; y+=1; } public void paint (Graphics g) { super.paint(g); g.fillOval(x, y, 30, 30); } public static void main(String[] args) { JFrame frame = new JFrame("Animation"); Game game = new Game(); frame.add(game); frame.setVisible(true); frame.setSize(300,400); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setResizable(false); while (true) { game.moveBall(); game.repaint(); } } } 
8
  • Actually, it probably was, the problem mostly likely is, it simply moved so fast that it was never updated to the screen... Commented Dec 14, 2014 at 22:51
  • Probably the problem: you try to move the ball in a while loop. Either this will move way too fast, or it won't even appear in the frame because the frame itself isn't being repainted. It's probably not that the frame isn't being repainted because you don't even see an oval. Use a Timer Commented Dec 14, 2014 at 22:51
  • Ok, so how would i reduce the speed? Is is possible/easier to do this with threads? Is that what thread.sleep(millisecond param) does? @MadProgrammer Commented Dec 14, 2014 at 22:52
  • How would this be done? @Quincunx Commented Dec 14, 2014 at 22:53
  • 1
    For a JPanel the public void paint (Graphics g) { super.paint(g); code should be public void paintComponent(Graphics g) { super.paintComponent(g);.. Commented Dec 14, 2014 at 23:17

2 Answers 2

7

The likely problem is, that thread is running too fast for the UI, the UI is been shown well after the "ball" has left the visible area.

You need to do a couple of things...

First, you need to make sure that the updates are scheduled properly within the Event Dispatching Thread and secondly, that there is a short delay between updates. For example, 25fps is about a 40 millisecond delay between updates, 60fps is about 16 milliseconds

There are a number of ways to achieve this, depending what it is you hope to achieve, for example, you could simply use Thread.sleep to cause the thread to pause for a small amount of time between updates. The problem with this is Swing is not thread safe and all updates to the UI should be made within the context of the Event Dispatching Thread.

While you program is only simply, it's possible that a paint cycle could run while you updating it's state, resulting in a dirty update.

Another solution might be to use a Swing Timer which will allow you schedule updates at a regular interval which are triggered within the context of the Event Dispatching Thread, making it safer to use.

Have a look at Concurrency in Swing and How to use Swing Timers for more details.

As an example...

Moving Ball

import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; 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; public class BallAnimation { /** * @param args the command line arguments */ public static void main(String[] args) { new BallAnimation(); } public BallAnimation() { 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 int x = 0; private int y = 0; public TestPane() { Timer timer = new Timer(40, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { moveBall(); repaint(); } }); timer.start(); } protected void moveBall() { x++; y++; } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); g2d.setColor(Color.RED); g2d.fillOval(x, y, 30, 30); g2d.dispose(); } } } 

As a side note, unless you really have reason to do so, you should avoid overriding paint and instead use paintComponent

Sign up to request clarification or add additional context in comments.

6 Comments

Ok, this helps a lot. Thank you for recommending threads as unsafe. All I added was the Game constructed with the statements for the timer inside and it works. However, I am slightly lost with what is in the lines of the BallAnimation constructor (except for the frame statements). Could you summarize what this is exactly and why it is necessary? Thanks in advance. @MadProgammer
Basically, EventQueue.invokeLater is ensuring that UI is created and shown from within the context of the Event Dispatching Thread (making it thread safe), see Initial Threads for more details. UIManager.setLookAndFeel is just setting the look and feel used by Swing to the current System's look and feel, I don't like the metal look at feel
So if I use EventQueue.invokeLater to make the program thread safe, would I then be able to safely use Adem's thread method? @MadProgrammer
No. The "main" thread (which calls the main method) and the Event Dispatching Thread are two different threads. Updating the UI from the "main" thread (or any other thread) would violate the single threading rules of Swing. The "simple" solution is to use a Swing Timer as it synchronises the updates required by the UI within the context of the EDT (you can't update the state AND paint at the same time). You could do this manually, but it increases the complexity of the solution.
If you were to use a BufferStrategy, you could gain control of the paint process, then it wouldn't matter so much, but you increase the complexity of the solution...
|
-2

try your loop with sleep as simplest way to fit your code. main is actually a thread. and JFrame creates its own thread.

while (true) { game.moveBall(); game.repaint(); try { Thread.sleep(50); } catch (Exception e){} } 

and I just realized, you dont paint your whole screen with a default color.

change your paint method to this

public void paint (Graphics g) { super.paint(g); g.setColor(Color.white); //default color g.fillRect(0, 0, getWidth(), getHeight()); // fill whole canvas g.setColor(Color.black); //change color g.fillOval(x, y, 30, 30); // draw oval } 

10 Comments

FYI: Swing itself is not thread safe, while only a simple example, a more complex update process could cause dirty updates as paint cycles can occur independently of the programmers requests
yes, but he is just wanting to draw a simple oval shape. as my explanation, this is the simplest way
"and I just realized, you dont paint your whole screen with different color." - paint, via a call to paintComponent (via calling super.paint) will do this. See Painting in AWT and Swing and Performing Custom Painting for more details
Simple and misleading
If that's your approach, then you've been doing it wrong. If you were to teach someone to shoot, you wouldn't just show them how to pull the trigger. You'd teach them about gun safety first. Same thing here. We need to teach people how to work within the requirements of the API/framework, which will help prevent them from "shooting themselves in the foot" as they increase the complexity of the problem. Build from a strong foundation and your house won't fall down around ;)
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.