I am having an issue painting a JPanel. It paints correctly, however when I resize the parent container, the JPanel gets painted at the top left corner of the window, as well as in the correct position.
The JPanel has a custom paint method, that paints a set of components that don't belong to any JPanel (including it). These are added to the JPanel immediately before their paint method is called, and is removed immediately after:
paintOnto.setIgnoreRepaint(true);
paintOnto.add(getPaintableComponent());
getPaintableComponent().paint(g);
paintOnto.remove(getPaintableComponent());
paintOnto.setIgnoreRepaint(false);
paintOnto is a reference to the JPanel, getPaintableComponent() returns a JComponent that is to be drawn. g is the Graphics object passed through from the JPanel paint method.
The add/remove code was not required in mac at all, but under windows without it the components didnt paint at all.
This issue is only present in windows and ubuntu, not mac. Other systems are untested.
Any ideas what could be causing it? I have checked the position of the JPanel whenever it is painted, and it never is positioned at the top left corner.
Thanks
TRy to save AffineTransform of the graphics before and restore it after painting.
Related
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.
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.
I have been trying to paint the graphics of an Applet when Applet.setVisible(false); and painting it onto my JPanel when JPanel.visible(true);
I tried to use Image i = Applet.createImage(width,height); and then paint the image to my JPanel with g.drawImage(i, 0, 0, this);
All I am left with is a blank JPanel when JPanel.paintComponent(Graphics g)... is invoked.
Is there a better approach to this?
If I'm not mistaken, the Applet won't draw when it's visibility is set to false, which explains why your JPanel is coming up blank. Is it necessary for you to hide the Applet? A typical solution would be to add the Applet directly to the JPanel by calling:
myJPanel.add(myApplet);
Of course, this mixes Swing and AWT components, which some people will object to, but it still works. Note however that a single instance of an Applet cannot be drawn to two places at once, so you cannot add your Applet to the JPanel and another place at the same time.
In my code I override the paintComponent method and draw a rectangle inside JPanel.
The JPanel is then added to JFrame and I use a method that updates the position of the rectangle via a Thread.
The rectangle does actually move .. but only when I minimize the window and maximize it back again. So in other words.. it doesn't do it as I'm looking at it.. the rectangle will just sit there.. but after I minimize and bring the window back up, the rectangle will have moved.
What can I do to fix this?
I am guessing you forgot to call the Repaint of the JPanel whose paintComponent you are overriding everytime you update the object. The reason you are only seeing the change on minimize/maximize is because that is when swing calls the repaint of the component.
I set the background of a JWindow completely transparent. Then I painted a rounded Rectangle (RGB: 0,0,0,100) in it's paint-Method and added a JLabel to the JWindows ContentPane. But when I try to repaint the JWindow to update the JLabel, it doesn't remove the old Rectangle and the old value of the JLabel. So the result is that my custom tooltip box (what it should be) gets less transparent and you cannot read the JLabels contents, because it overlays the old contens.
Is there any way to solve this problem?
BTW, if I don't repaint, it doesn't get less transparent, but the new contents of my JLabel overlays the old Contents, like it is, when I repaint.
First you should override paintComponent instead of paint and call super.paintComponent(g). You should leave JWindow opaque, because the component on the rearmost layer will clear the old contents. If all the layers are transparent you will end up with screen garbage.
See painting with Swing. Perhaps you really wanted to create translucent windows?