1

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

Frakcool
  • 10,915
  • 9
  • 50
  • 89
Eitanos30
  • 1,331
  • 11
  • 19
  • *I expect that the JPanel background color will be black* - why? The painting of the background doesn't just magically happen. The logic for painting the background is contained in the default implementation of the `paintComponent()` method of the `JPanel`. You overrode the method, but you don't do any custom painting. If you want the default behaviour, then you need to invoke super.paintComponent(g). You should NOT be overriding the paintComponent() method to change a property of the JPanel. – camickr Jun 24 '19 at 20:50

1 Answers1

2

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.

Frakcool
  • 10,915
  • 9
  • 50
  • 89
  • Thanks.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. The only difference i have noticed, is that JPanel background stays with it's default color.So it seems that although "breaking" the chain,JPanel still being painted.How is it possible?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? – Eitanos30 Jun 24 '19 at 20:46
  • 1
    Yes, just don't delete and add new comments. I'm currently busy. Will get back to you in about ~2 hours. In the mean time, please post a [mcve] that I can use to explain to you. I.e. 1 with the background color set with the random and static color, and try to clarify a little bit what you're trying to understand (as specific as possible) so it's easier for me to answer. – Frakcool Jun 24 '19 at 20:50
  • @Eitanos30, The paintComponent() method should NOT set a random Color. Whenever a property of a Swing component is changed to a new value, the component is automatically repainted. So if you generate a new random color the paintComponent() method will get invoked and a new Color will be generated and paintComponent() is invoked again causing a loop. As you have already been told `don't change the property of a component in the painting method`, The painting method should only paint the current state of the component. – camickr Jun 24 '19 at 20:58
  • Please see the updated answer, and trust @camickr he's one of the top 10 users in the Swing tag in Stack Overflow. – Frakcool Jun 25 '19 at 01:25
  • @camickr,@Frakcool,your both replies helped me a lot(thanks).Can you explain me some things i still don't understand in your explanation:1.Does the random makes the code to make infinite recursion?2.What exactly do you mean when you say:"the painting method should only paint the current state of the component"(maybe an example of what can be written and what shouldn't)?3.What do you mean when saying:"You overrode the method, but you don't do any custom painting".What does it mean custom painting?4.Does JPanel children(JButton,JLabel,etc) also has paintComponent method that can be overriden? – Eitanos30 Jun 25 '19 at 15:48
  • 1
    **1)** No, it's not recursion, is like a loop. Recursion = The method calls itself; a loop = a method gets called multiple times. In this case is **like** a loop (not a loop itself), but you have no control on when it gets called. **2)** See this [example](https://stackoverflow.com/a/34748083/2180785), the app paints the current state in every iteration. I.e. the background changes when the Timer fires an event, changing both the text and background color every second. – Frakcool Jun 25 '19 at 15:56
  • 1
    **3)** Read the [tutorial on custom-painting](https://docs.oracle.com/javase/tutorial/uiswing/painting/index.html), it means to draw any figure you want on it, such as [snakes](https://stackoverflow.com/a/56462363/2180785), [circles](https://stackoverflow.com/a/41703107/2180785) or other [shapes](https://stackoverflow.com/a/41944799/2180785) or even [drawings](https://stackoverflow.com/a/48792882/2180785) inside the `paintComponent` method of a `JComponent` such as `JPanel` or `JButton`, etc. **4)** Yes as they all extend from `JComponent` and that's a method defined by this super class – Frakcool Jun 25 '19 at 16:04
  • 1
    Please see the above comments @Eitanos30 and if this answer solved your question, be sure to accept it. The link to `JComponent#paintComponent` method is on the answer itself. And [here](https://docs.oracle.com/javase/7/docs/api/javax/swing/JLabel.html) you can see that a `JLabel` extends from `Object > java.awt.Component > java.awt.Container > javax.swing.JComponent`. Same would happen for a `JButton` and as they are all components you can set `layout-managers` to them as well, [for example](https://stackoverflow.com/a/42169894/2180785) – Frakcool Jun 25 '19 at 16:04