7

I want to start building my own customized JComponent's for a project at work. I have a simple example below that should just create a ball on the screen. (I found most of it on the internet) but it does provide a decent starting point. My question is why does this code not show the ball in my form? What have I done wrong?

Also what would be all of the basic methods that SHOULD be provided for a custom JComponent?

Code:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class testBall {
    public static void main(String[] args) {
        new testBall();
    }

    public testBall() {
        JPanel testPane = new JPanel();
        testPane.setBackground(Color.white);
        testPane.setLayout(new GridBagLayout());
        testPane.add(new MyBall(30,30,10));

        JFrame frame = new JFrame("Testing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(testPane);
        frame.pack();
        frame.setSize(500, 300); 
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

class MyBall extends JComponent
{
    private static final long serialVersionUID = 1L;
    public MyBall() { }
    public MyBall(int x, int y, int diameter)
    {
        super();
        this.setLocation(x, y);
        this.setSize(diameter, diameter);
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.setColor(Color.red);
        g.fillOval(0, 0, 100, 100);
    }
}

Where I could find a list of all of the methods that should be overridden in a JComponent class? (I know there are ones that should always be included in JComponent.)

If I make an instance of this component in a class and need to change the color of the circle would I just call there repaint() method from that class?

Draken
  • 3,049
  • 13
  • 32
  • 49

3 Answers3

6

You are adding the MyBall to testPane (which has a GridBagLayout) without specifying any constraints. (That is, your call to add() has no second parameter.) The default constraints are most likely not what you want. Try using BorderLayout for your test pane, as this uses BorderLayout.CENTER as the default, which is probably reasonable in your case:

testPane.setLayout(new BorderLayout());

This causes the ball to show up for me.

As for your second question, I think your class is fine as defined. The main method you want to implement is paintComponent() as you have. Sometimes it becomes necessary to override the get min/max/preferred size methods, but it really just depends on what you want the component to do. JComponent is not abstract, so you don't have to override anything if you don't want to. It provides a lot of functionality out of the box such as keyboard focus, pluggable look-and-feel, accessibility, etc. As long as you don't want to change any of that stuff, just leave it as is. Implement paintComponent() and the various get*Size() methods and be done with it. (You just kind of have to pick through the methods in the JavaDoc to see what is appropriate to override.)

The other option is to extend a subclass of JComponent, if there as a class that does something similar to what you want to do. For example, JPanel is often a good starting point for impelmenting your own container.

You were probably looking for something more concrete than 'it depends', but right now, if all you want is to draw a ball, then simply override the methods that deal with the rendering of the JComponent (paintCompentent(), and the get*Size() methods).

As a side note, you really should be using SwingUtilities.invokeLater() to create your Swing components on the Swing thread. See the section entitled "Swing's Threading Policy" at http://docs.oracle.com/javase/6/docs/api/javax/swing/package-summary.html.

matt forsythe
  • 3,153
  • 1
  • 14
  • 27
  • If you wanted a list of all of the methods that could or should be included in JComponent were would I find that? –  May 05 '14 at 19:30
  • In my test method what if I want to repaint the Jcomponent green when I click on the form. Can I just call repaint() and that should repaint every component on the form correct. –  May 05 '14 at 19:31
  • @user3376708 Updated the answer to address your first question. For your second question, yes - I think all you need to do is call repaint() on the `MyBall`. – matt forsythe May 05 '14 at 19:51
  • `Sometimes it becomes necessary to override the get min/max/preferred size methods,` - that needs to be done all the time when creating a custom component. You need to implement those methods so that layout mangers can function properly. The solution to use a BorderLayout does not fix the problem. Try adding the component to the NORTH of the BorderLayout and you will still have the same problem. – camickr May 05 '14 at 20:09
  • Why will this not work in different layouts? If was making a real component wouldn't i want to make the component so that it could be used in every layout form. –  May 05 '14 at 20:25
  • @camickr I say "_sometimes_ it becomes necessary", because it just depends on how you intend to use it. Some layouts thrust a size onto your component and completely ignore size info. For some components that may make sense (for example, if your component is just trying to draw something nice to take up empty space). Switching to `BorderLayout` does solve the issue in that the default for BorderLayout is CENTER, which will allow the component to show. – matt forsythe May 05 '14 at 20:34
  • What camickr is saying is that you really should implement the `get*Size()` methods so that layout managers can do their job. Many layout managers use max, min, and preferred size to determine how to allocate space in the container to the various components inside of that container. If you don't implement those methods, then your component will not play well with others (or even by itself) when used with those layouts. This may work if don't use your component in those containers, but is not really "proper". This is why your component doesn't work with GridBagLayout. – matt forsythe May 05 '14 at 20:48
  • One more comment on whether or not to override the `get*Size()` methods: Often it is not necessary to override the methods because you can simply call the corresponding setter methods in the constructor (if you know your min/max/preferred size up front). Then the component will work properly with the layout managers. I say this because the getters for these properties are actually non-trivial, so overriding them is a little heavy-handed unless you need to. Overriding may still be needed, though, if your sizes need to be calculated dynamically. – matt forsythe May 06 '14 at 14:04
1

Made some tweaks around your java class, the only change i did was add your new MyBall directly to the content pane of the JFrame, try to run this and you will see a red circle on your jframe

public class TestBall {
    public static void main(String[] args) {
        new TestBall();
    }

    public TestBall() {

        JFrame frame = new JFrame("Testing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.getContentPane().add(new MyBall(30,30,10));
        frame.pack();
        frame.setSize(500, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

class MyBall extends JComponent
{
    private static final long serialVersionUID = 1L;
    public MyBall() { }
    public MyBall(int x, int y, int diameter)
    {
        super();
        this.setLocation(x, y);
        this.setSize(diameter, diameter);
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.setColor(Color.red);
        g.fillOval(0, 0, 100, 100);
    }
}
rahul pasricha
  • 901
  • 1
  • 13
  • 32
0

Constructor: we just set location to the points, which are passed throught constuctor parameters. This is the place, in which this component will be located. The same way we set the size (width x height).

paintComponent: here we just paint some oval over passed graphics object.

The other part is just the test, which shows, that the component is correctly created and shown.

Dmitry Ginzburg
  • 6,947
  • 2
  • 33
  • 48