Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw and move a circle in Java

I'm using Swing to create a small GUI in Java. All I am trying to get it to do is take an ArrayListof Circles and draw them. I've run into two problems:

1) I have to call my draw method repeatedly before it draws the circle. If I just call my draw method once nothing happens, I get a blank drawing. If I call it in a loop that runs for less than 30 milliseconds it only draws the first of two circles that I want to draw. Finally, if I call it for more than 30 milliseconds it draws both circles I am trying to draw.

and

2) When I move one of the circles, I get a "flicker" on the drawing.

I'm not too familiar with Swing programming. I've looked at sample code and watched a few videos - and what I have looks right to me. But I figure I must have messed something up, because it doesn't look like this in the videos I've watched.

Here is my GUI class:

package gui;

import draw.*;
import java.util.List;
import javax.swing.*;

public class GUI extends JFrame {
    private CirclePainter drawingBoard = new CirclePainter();

    public GUI()
    {
        setSize(500, 500);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.add(drawingBoard);
        drawingBoard.setVisible(true);
    }

    public void draw(List<Circle> circles)
    {
        drawingBoard.paintComponent(drawingBoard.getGraphics(), circles);
    }
}

my CirclePainter class

package gui;

import draw.Circle;

import javax.swing.*;
import java.awt.*;
import java.util.List;

class CirclePainter extends JPanel
{
    public void paintComponent(Graphics graphics, List<Circle> circles)
    {
        super.paintComponent(graphics);
        for(Circle circle : circles)
            graphics.fillOval(circle.getX(), circle.getY(), circle.getRadius() * 2, circle.getRadius() * 2);
    }
}

EDIT: redacted some code since this is for a school project. The remaining code should be enough for someone visiting in the future to still understand the question.

like image 310
ThomYorkkke Avatar asked Mar 01 '26 10:03

ThomYorkkke


1 Answers

  1. Never call paintComponent(...) directly as you're doing.
  2. Instead suggest a draw by calling repaint() on a component when necessary.
  3. Don't draw with a Graphics object obtained via a getGraphics() call on a component. Instead, draw with the Graphics object provided in the paintComponent method.
  4. Avoid using while (true) loops in a Swing GUI as you risk tying up the Swing event thread and freezing the GUI. Use a Swing Timer for simple animations.
  5. You probably don't even need a Swing Timer since your animation can be driven by your MouseListener/MouseMotionListener.
  6. Most important -- do read the Swing painting and other tutorials, as most of this information can be found there. It looks like you're guessing how to do some of your coding and that's a dangerous thing to do when it comes to drawing or animating a GUI. You can find most tutorials in the Swing info link.
  7. Consider using a Shape object to represent your Circle, such as an ellipse2D. The reason that this will help is that it has some very useful methods, including a contains(Point p) method that will help you determine if a mouse click lands inside of your circle.
  8. You will want to decide where _x and _y represent the center point of your circle or not. If so, then you'll need to adjust your drawing some, by shifting it left and up by _radius amount.
  9. Consider casting your Graphics object into a Graphics2D object in order to use its extra methods and properties.
  10. One such property are the RenderingHings. Set your Graphics2D RenderingHints to allow for anti-aliasing to get rid of your image "jaggies". This can be done with: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); where g2 is your Graphics2D object.
  11. Your paintComponent method is not a true paintComponent override and thus won't work correctly. It should be a protected method, not public, it should have one parameter, a Graphics object, and nto a second parameter, and you should place the @Override annotation above it.

For example, please have a look at this answer of mine to a similar problem.

An example of a paintComponent method that centers the circles on _x and _y and that uses rendering hints:

class CirclePainter extends JPanel implements Iterable<Circle> {
   private static final int PREF_W = 500;
   private static final int PREF_H = PREF_W;
   private CircleList circleList = new CircleList();

   @Override
   protected void paintComponent(Graphics graphics) {
      super.paintComponent(graphics);
      Graphics2D g2 = (Graphics2D) graphics;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      for (Circle circle : circleList) {
         // if x and y are the center points, then you must subtract the radius.
         int x = circle.getX() - circle.getRadius();
         int y = circle.getY() - circle.getRadius();
         int width = circle.getRadius() * 2;
         int height = width;
         g2.fillOval(x, y, width, height);
      }
   }
like image 180
Hovercraft Full Of Eels Avatar answered Mar 02 '26 22:03

Hovercraft Full Of Eels



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!