9

I have a very simple problem. I am learning Java, and was given an assignment to draw a car. I did this all in one class that extends JPanel, and did the drawing within paintComponent().

I realize this is poor object-oriented programming, and decided to try to subclass some of the parts to rectify this situation.

I tried to create a class that draws wheels, but was unsuccessful.

Essentially, I wanted to be able to do this:

Main Class extends JPanel

paintComponent{
       Wheel leftWheel = new Wheel(0, 50, 100);
       this.add(leftWheel);
}

This should draw a wheel at the point (0, 50) within the JPanel, and have a diameter of 100.

However, i'm unsure how i'm supposed to control the positioning in the JPanel. When I do this, the wheel in drawn at the top center of my window. This is what my wheel class looks like:

public class Wheel extends JComponent {

private int x, y, diameter;
private boolean clockwise;

Wheel(int x, int y, int size, boolean cw)
{
    this.setPreferredSize(new Dimension(size, size));
    this.x = x;
    this.y = y;
    diameter = size;
    clockwise = cw;
    repaint();
}

public void paintComponent(Graphics canvas)
{
    super.paintComponent(canvas);
    canvas.setColor(Color.gray);
    canvas.fillOval(x,y,diameter,diameter);
}

}

The x and y should be where it appears on the parent window, however, this is not the case in the following code (located in the parent class that extends JFrame):

Wheel leftWheel = new Wheel(0,0,WHEEL_DIAMETER,true);
this.add(leftWheel);

The wheel doesn't draw at the top left of my window, it draws in the center of my window at the top. Am I doing something incorrectly? Sorry if I don't follow some Java conventions, I don't have any experience yet. Is this how I should be handling the drawing of the wheel, or is there a more accepted practice for doing this type of drawing?

For example, in my JPanel class, if I add the following code:

Wheel x = new Wheel(50,60,75,true);
this.add(x);

I get a frame sized 75x75 in which a wheel (sized 75x75) is drawn at the point (50,60) within that frame, not within the parent JPanel's coordinate system. The result is a circle that gets clipped and I only see the top left of the circle. That image is displayed at the top center of my JPanel

I understand how to draw the wheel, and move it within itself, but how do I position the wheel on the JPanel??

Josue Espinosa
  • 4,642
  • 14
  • 43
  • 80
  • 1
    From an encapsulation point of view, I'd move the positioning logic entirely outside of the `Wheel` class. It is the business of the class that assembles the car to “mount” the wheel at the correct position. – 5gon12eder Sep 18 '14 at 20:22
  • I agree. How would I control the positioning in the parent class? That is what I don't understand. I am unfamiliar with Java and it's syntax. – Josue Espinosa Sep 18 '14 at 20:23
  • 1
    You can use the overloaded `add` method that accepts a constraints object to control the positioning. How you'll do this exactly depends on the [`LayoutManager`](https://docs.oracle.com/javase/7/docs/api/java/awt/LayoutManager.html) you are using. – 5gon12eder Sep 18 '14 at 20:31
  • 1
    As an aside, if you are using Eclipse, you might find it useful to use WindowBuilder, as an example, to see what the render looks like without having to recompile and run bit by bit. – Compass Sep 18 '14 at 20:39

3 Answers3

6

Your constructor has a small bug,

Wheel(int x, int y, int size, boolean cw) {
  this.setPreferredSize(new Dimension(size, size));
  diameter = size;
  clockwise = cw;
  repaint();
}

You forgot to store x and y. I think you wanted,

Wheel(int x, int y, int size, boolean cw) {
  this.x = x;
  this.y = y;
  this.setPreferredSize(new Dimension(size, size));
  diameter = size;
  clockwise = cw;
  repaint();
}

Because your x and y are 0 if you don't set them.

Elliott Frisch
  • 183,598
  • 16
  • 131
  • 226
  • Hmmm, I added the lines I forgot, but now the wheel isn't drawn at all. I did not change any other code. – Josue Espinosa Sep 18 '14 at 20:12
  • @JosueEspinosa Perhaps you should make sure that x and y aren't past the edge of your window. – Elliott Frisch Sep 18 '14 at 20:13
  • Yes, that was it, but the coordinates control where the wheel is drawn in it's own window, not the parent. Could you explain how to control it's location within the JPanel, not within itself please? – Josue Espinosa Sep 18 '14 at 20:14
3

Could you explain how to control it's location within the JPanel, not within itself please?

The default LayoutManager for a JPanel is a FlowLayout so the component will always be positioned based on the rules of the layout manager.

If you want to add components to a random location then you need to use a null layout. But when you use a null layout you are then responsible for setting the size and location of the component. So, in reality the custom painting should always be done at (0, 0) in your custom component.

camickr
  • 308,339
  • 18
  • 152
  • 272
0

Instead of adding multiple JPanels to create the vehicle I would simply use one class that extends JPanel and create multiple methods to create things such as wheels etc. to be called from within the overridden paintComponent method. You can pass the new method a reference of your graphics object, create a copy of your graphics object using g.create(), or use getGraphics() from inside the method itself. Inside the method to create a wheel you then are able to calculate it's position by using the panel's dimensions and place it properly.

An alternative would be to define and return shapes in other methods and simply draw them using the graphics object in paintComponent().

MarGar
  • 465
  • 4
  • 12