Can't understand JPanel setBackground method behavior - java

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

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.

Related

Passing a JPanel to a method to draw rectangles

I have a class with a draw method that accepts a JPanel as an argument.
The first line in the draw method is:
Graphics g = p.getGraphics();
Where (p is the the jPanel passed as an argument to the draw(Jpanel P) method).
I want to draw different rectangles in different colors (based on conditional statements). So i use the
g.setColor(Color.RED) // or another color
Then i draw the rectangle using
g.fillrect(x,y,xsize,ysize).
When i do
System.out.println("color is " + g.getColor().toString());
I see the colors changing, but i don't see the rectangles appearing on the JPanel. This JPanel is an object inside my class that extends from JFrame. What do i need to do to see the rectangles on my JPanel?
You should not paint by obtaining the Graphics object from the JPanel. What you should do is to subclass JPanel and override paintComponent, check this.
The reason why is because the Graphics instance is created everytime your Panel is painted, and you have no control about it, because its parent (the JFrame) may decide when to do so. So you should never make any assumption about the Graphics instance, and you must include your painting logic in the paintComponent method.
The reason why you are not seeing your rectangles is because you are painting them with either an old Graphics instance, or because in the next rePaint they are getting erased because is not the order it is supposed to be (those calls must be in the paintComponent method).
JPanel doesn't know that its canvas is updated, so you see nothing on the screen. The proper way is to override JPanel's method onPaintComponent and draw inside this method. This way, after you call JPanel.repaint() you'll see the stuff you've drawn.

paintComponent called continuously

Similar problem here but didn't find an answer: Why is paintComponent() continuously and asynchronously being called without explicit repaint() call?
I have a JPanel that I am drawing onto
class DrawPanel extends JPanel {
final void paintComponent(Graphics g) {
super.paintComponent(g);
// some graphics drawing stuff
} }
and then adding this to a JScrollPane. However if I put a system.out.println() in the paintComponent method I can see its continuously being called. Any way to stop this? According to the link its possible due to the jpanel being covered
Generally paintComponent() does not paint continually. It get invoked occasionally when Swing determines it needs be painted.
If your method is being invoked continually then I can think of a couple of possible problems. You are:
manually invoking repaint()
changing a property of the component in the paintComponent() method which then automatically invokes repaint()
The paintComponent calls come from Swing's Event Dispatch Thread. It gets called everytime the component needs to be repainted.
If you resize the component or bring it back from minimized state, then it's repainted. Of course if you cover it with another component then the repainting will be called less. The other component will have a paintComponent method too though.
Nothing to worry about.

Understanding Swing and repaint()

I am trying to understand how painting with Swing works. For that purpose I've been reading the Oracle tutorial: http://docs.oracle.com/javase/tutorial/uiswing/painting/step3.html
My question is a simple one:
Why do the two calls to the same function (repaint) have different behaviour? How does it come that the UI Delegate paints the background on the previously painted rectangle, but paints a new rectangle on the new area? I don't see any particular reason on paintComponent() for that.
I have also read http://docs.oracle.com/javase/tutorial/uiswing/painting/closer.html trying to understand the situation. It seems there is some connection to the opaque property of a component. Does this property change after we create a new rectangle, so that it is true (thus, as mentioned, the ui.update() will set it to the background color). How come it paintComponent() doesn't paint a new rectangle there?
The function is called with different parameters:
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
squareX=x;
squareY=y;
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
In the first call to repaint() squareX and squareY indicates location of the previously painted object. In second the second call, squareX and squareY is changed to the current mouse location.
From JComponent API documentation on repaint():
Adds the specified region to the dirty region list if the component is
showing. The component will be repainted after all of the currently
pending events have been dispatched.
That is, the first call to repaint() marks the previous location as dirty, the second, marks the current location as dirty. When the event (moveSquare) is completed, paintComponent is re-executed, and these two areas are updated. The red rectangle is only placed in the new location, the old location is updated to be "empty".
You are right about the opaque property, which is true for typical PanelUI implementations. In particular, paintComponent() says,
if you do not invoke super's implementation, you must honor the opaque property...If you do not honor the opaque property you will likely see visual artifacts.
Your code does honor the opaque property by invoking super.paintComponent(g). Both calls to repaint() clear the drawing rectangle to the background color. Try setting a different background color in the MyPanel constructor and omitting the super call to see the effect:
public MyPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
setBackground(Color.cyan);
...
}
#Override
protected void paintComponent(Graphics g) {
//super.paintComponent(g);
g.drawString("This is my custom Panel!", 10, 20);
...
}

How to successfully modify the way a JFrame (and all of its components) paint?

I'm trying to implement a simple window scale in java's swing library. The goal is simply to double the window height and width, and paint the window and each of its components in scale.
Here's an example of the code I'm using:
public class MyWindow extends JFrame {
...
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.scale(2,2);
super.paint(g);
}
}
The position and size for each my components in this window is set manually using setBounds with a null layout for the window.
When I actually run the program, what happens is that the first paint for the window seems successful-- everything is sized appropriately. Each subsequent repaint by the components, however, is neither twice the size, nor in the proper location. Here's what I mean:
As you can see, portions of the screen which have components that call repaint manually (the animating bits), don't seem to be using the Graphics2D scale of the JFrame. I looked in the source code, and tried overloading a few other methods (update and repaint, mostly), but all of them seemed to produce the same result. I further looked at the paint and repaint methods of the component and container classes, but they all seem to call a specified repaint of their parent. Shouldn't my Window be the "biggest" parent? If so, why haven't these repaint calls reached my Window?
My big question to you is, therefore: what repaint methods of the parent component do the child components call? Why aren't the calls properly routed to my JFrame's paint call? Is there any other (better) way that I can scale my window? Any and all help is appreciated!
As discussed in Painting in AWT and Swing: The Paint Methods, "Swing programs should override paintComponent() instead of overriding paint()." A common approach is to create a view by overriding paintComponent() in a JComponent (or subclass), as shown here. Let your view listen for changes to the game's model, as discussed here.
SwingUtilities.updateComponentTreeUI() should be used to change the Look & Feel, not update the view.
Use
javax.swing.SwingUtilities.updateComponentTreeUI(parentComponent);
when you need to make sure all of the parentComponents child component's look and feel are updated properly.

Content of JDesktopPane dissappears when resized - Java Swing

I have been working on Java Swing for a while. I paint something(draw some basic shapes like circle,rectangle etc) on a JDesktopPane and once I resize the frame window that contains jDesktopPane or drag some other window over this frame, then the drawn shapes disappear. I use an object of the BufferedImage class so as to save the image. So Is there any way of preventing the shapes getting disappeared or repaint it when they disappear?
You need to make sure you are saving what you paint and repainting it each time in the paintComponent() method. This method is called automatically whenever a repaint is needed (for example: because of a resize).
I can only provide a guess since you've decided not to post the necessary code, but my suggestions are:
Don't get your Graphics object by calling getGraphics on a component. Instead,
Be sure to do your drawing in a class that subclasses a JComponent or one of its children (such as a JPanel).
draw your BufferedImage in the JComponent's paintComponent method immediately after calling super.paintComponent() in the same method. Use the Graphics object that is provided by the JVM and passed into the method's parameter.
To be sure that your paintComponent method's signature is correct, place an #Override annotation immediately before it. Otherwise if it is not correct, the JVM will probably not call it when you expect it to.
But also, please when asking a question here, try to give us enough information so we don't have to guess. Since your problem is graphics related, it would make sense to post your graphics-related code, right?

Categories

Resources