Search code examples
javaswingoverridingjlabelpaintcomponent

Can't understand JPanel setBackground method behavior


JPanel.setBackground method does nothing (although opaque attribute is true) if super.paintComponent father method isn't being called.

I have read a lot of similar questions here about this issue, and in each one of them I've only found solutions without explanation that helped me to understand why setBackground method when written before adding the JPanel to JFrame changes the JPanel background color, while when the setBackground is written inside paintComponent nothing is changed (only when calling father's paintComponent method as already mentioned). Is it somehow related to Graphics object?

I have tried to change JPanel's opaque attribute to true and using setBackground(COLOR.BLACK) in paintComponent() method I had overriden in a class that extends JPanel

  paintComponent(Graphics g)
    {
      this.setOpaque(true);
      this.setBackground(COLOR.BLACK);
    }

I expect that the JPanel background color will be black

Instead, background color is the default one


Solution

  • Well, first of all if you're using paintComponent(Graphics g) method, the first line you need to have inside is: super.paintComponent(g) otherwise you're breaking the paint-chain.

    This will allow the parent component to draw the default component, before any customizations you do to it. If you don't do it, well, is like having a drawing in a piece of paper, imagine a circle, then cutting that circle and then trying to paint the outside.

    Here's a more in-depth answer to How does super.paintComponent(g) works

    However I wouldn't write

    this.setOpaque(true);
    this.setBackground(COLOR.BLACK);
    

    inside the paintComponent(...) method, as it gets called several times and you can't control when it will ever get called. I would put those lines in a constructor, unless you want to change it later in your program while it's being painted depending on the state of your program or a gradient maybe.

    For this part:

    why setBackground method when written before adding the JPanel to JFrame changes the JPanel background color

    Honestly, I don't understand what you mean.


    Why do you say that if i won't call super.paintComponent(),it will break the chain? It's still drawing all the shapes and lines i want using graphics object.

    From the docs:

    The JPanel has a UI delegate which performs the background painting for itself. You call it by using super.paintComponent(g) and we pass the Graphics component to prevent irrevocable changes such as Graphics.translate

    Your JPanel knows how to paint its children, but requires some help to paint itself, and this help comes from its parent.

    When I mentioned "break the paint chain" I didn't mean nothing would paint, but that you would get strange behaviors such as the one of the JPanel's background disappearing or not being set.

    In addition,something weird happens if the argument i'm sending to setBackground method is a random color(using Random object). JPanel changing color very quickly although i'm not doing anything(not minimizing,not resizing,etc).Can you consider why?

    As I said before, the paintComponent gets called several times and you don't have control over when it will be called, even moving your mouse or something else will trigger the panel to repaint.