7

I have a custom component that extends JComponent, which overrides the method paintComponent(Graphics g) but when I try to add it to my JPanel it just doesn't work, nothing is drawn. Here is my code:

public class SimpleComponent extends JComponent{

int x, y, width, height;

public SimpleComponent(int x, int y, int width, int height){
    this.x = x;
    this.y = y;
}

@Override
public void paintComponent(Graphics g){
    Graphics2D g2 = (Graphics2D) g;
    g2.setColor(Color.BLACK);
    g2.fillRect(x, y, width, height);
}
}


public class TestFrame{
public static void main(String[] args){
    JFrame frame = new JFrame();
    JPanel panel = new JPanel();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    panel.setPreferredSize(new Dimension(400, 400));
    frame.add(panel);
    frame.pack();
    frame.setResizable(false);

    SimpleComponent comp = new SimpleComponent(10, 10, 100, 100);
    panel.add(comp);
    frame.setVisible(true);
}
}
lilroo
  • 2,631
  • 7
  • 22
  • 31

2 Answers2

4

It works fine -- the component is being added to the JPanel, but how big is it? If you check this after the GUI has been rendered, you'll likely find that your component's size is 0, 0.

SimpleComponent comp = new SimpleComponent(10, 10, 100, 100);
panel.add(comp);
frame.setVisible(true);

System.out.println(comp.getSize());

Consider having your JComponent override getPreferredSize and return a Dimension that makes sense:

public Dimension getPreferredSize() {
  return new Dimension(width, height);
}

If you want to use the x and y, you may wish to override getLocation() as well.

Edit
You also need to set the width and height fields!

public SimpleComponent(int x, int y, int width, int height) {
  this.x = x;
  this.y = y;
  this.width = width; // *** added
  this.height = height; // *** added
}
Hovercraft Full Of Eels
  • 276,051
  • 23
  • 238
  • 346
-2

Whoaa! Absolutely not the right answer!

The first absolute CARDINAL SIN you have committed is to do all this in a non-EDT thread!!! There is no space to explain about this here... there are only about 30 billion places on the Net to learn about it.

Once all this code is executing in a Runnable in the EDT (Event Dispatch Thread), then:

You don't need to override preferredSize (although you can if you want)... but you do need to set it.

You absolutely shouldn't set the sizes (height and width, or setSize()) directly!

What you DO need to do is to get the java.awt.Container, panel, in your example, to "lay itself out"... there is a method Container.doLayout(), but as it says in the API documentation:

Causes this container to lay out its components. Most programs should not call this method directly, but should invoke the validate method instead.

the solution is therefore:

SimpleComponent comp = new SimpleComponent(10, 10, 100, 100);
comp.setPreferredSize( new Dimension( 90, 90 ) );
panel.add(comp);

// the key to unlocking the mystery
panel.validate();

frame.setVisible(true);

Incidentally, please profit from my experience: I have spent hours and hours tearing my hair out trying to understand all this validate, invalidate, paintComponent, paint, etc. stuff... and I still feel I've only scratched the surface.

mike rodent
  • 10,479
  • 10
  • 80
  • 104
  • Please see http://stackoverflow.com/questions/10866762/use-of-overriding-getpreferredsize-instead-of-using-setpreferredsize-for-fix?rq=1 – Hovercraft Full Of Eels Feb 19 '16 at 04:02
  • OK thanks... but if you were the person who downvoted my answer here that was not terribly helpful to future visitors to this question: my answer is far, far better than the accepted answer, and the nuance about `setPreferredSize`/`getPreferredSize` does not change that. – mike rodent Feb 19 '16 at 09:32
  • Oh... I see you were the answerer of the accepted answer! But with a rep of 214k you must surely know that every point I stated is right, and that your answer truly, um, how shall I put it, leaves room for improvement! – mike rodent Feb 19 '16 at 17:15