Parent panel not painted - java

I have the following Java Swing problem: a parent panel doesn't get painted (i.e. paintComponent() not even called) when it is covered by another panel which has a transparent background.
I guess this behavior is normal if the child panel isn't transparent but here it is an issue since the parent panel provides a picture as background.
Probably not relevant but you never know: child panel is a ChartPanel from JFreeChart's library (extends JPanel) and parent panel is also a JPanel extension, hereby the paintComponent code:
#Override
public void paintComponent(Graphics g) {
try {
long start = System.currentTimeMillis();
//Sets waiting cursor
GuiHelper.setCursorOnEntireWindow(Cursor.WAIT_CURSOR);
//Paints parent
super.paintComponent(g);
//Paints background and other elements
g.drawImage(generateBackground(getWidth(), getHeight()), 0, 0, getWidth(), getHeight(), this);
long end = System.currentTimeMillis();
System.out.println("Chart paint took: "+(end-start)+"ms");
}
finally {
//Removes waiting cursor
GuiHelper.setCursorOnEntireWindow(Cursor.getDefaultCursor().getType());
}
}
Any help/hint would be greatly appreciated as I've been looking into for hours now.
Thanks!

a parent panel doesn't get painted (i.e. paintComponent() not even called) when it is covered by another panel which has a transparent background
Not sure how you are setting the transparent background of ChartPanel. I think you just need to use:
childPanel.setOpaque(false);
If this doesen't work then check out Background With Transparency for more information on how painting is done between child/parent components.

As an alternative, consider the setBackgroundImage() method of org.jfree.chart.JFreeChart, which also has methods to control alignment and alpha.

Related

Stop JScrollPane from redraw JPanel

I have a JPanel with a JScrollPane sorounding it, the problem is that when i use the JScrollPane the JPanels redraw methode get called. I want to disable that because my JPanel redraw by its self at the right time.
I want it so it just updateds the getClipBounds() for the paint methode but withoud calling the paint methode.
You can't do that - since the viewport displays different parts of the contained JPanel, depending on the position of the scrollbar, the areas that have to be repainted might in fact be newly revealed and might not have been painted before.
Since JScrollPane doesn't know how the contained Component is implemented and whether it repaints its entire area or only the area that needs repainting, it forces the contained Component to redraw itself upon scrolling.
However, you can instead render the content you want to show to a bitmap, and then paint the bitmap in the paintComponent(Graphics) method. Thus, you effectively buffer your painted content and can initiate an update to the buffered bitmap whenever it suits you.
In order to paint onto a bitmap, you can do this:
BufferedImage buffer; // this is an instance variable
private void updateBuffer(){
// Assuming this happens in a subclass of JPanel, where you can access
// getWidth() and getHeight()
buffer=new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g=buffer.getGraphics();
// Draw into the graphic context g...
g.dispose();
}
Then, in your JPanel, you override the paintComponent method:
public void paintComponent(Graphics g){
g.drawImage(buffer, 0, 0, this);
}

my gui is taking too much resources in run time

I have a JFrame which contains a single panel.
In the panel I use the paintComponent method to resize its elements according the size of Jframe. The elements of the JPanel are an image as a background and 4 JLabel that cointains 4 ImageIcon and work like buttons. The method paintComponent of Jpanel is like below
public class MyPanel extends JPanel
{
//Declarations
private BufferedImage backGround;
public MyPanel()
{
//Some code here
}
public void paintComponent(Graphics graphics)
{
super.paintComponent(graphics);
Graphics2D graphics2d = (Graphics2D) graphics;
if(backGround != null)
{
graphics2d.drawImage(backGround, 0, 0, getWidth(), getHeight(), this);
}
/* This code is repeated 4 times because I have 4 labels */
label1.setSize(getWidth()/7 , getHeight()/10);
label1.setLocation(getWidth()/2 - getWidth()/14 , getHeight()/3 );
image1 = button1.getScaledInstance(label1.getWidth(), label1.getHeight(),
Image.SCALE_SMOOTH);
label1.setIcon(new ImageIcon(image1));
}
}
The frame has just a simple method , add(myPanel) so I did not write it here.
When I run the application , it takes me around 300 MB of ram and around 30% of CPU (Inter core i5-6200U) , which is quite unsual for me , expecially the amount of CPU. What is causing my application to take so much resources and is there any way I can reduce it ?
Whenever you repaint your component you change your labels' dimensions and create resources (the Image and the ImageIcon derived from it) and assign them as a new icon. These are changes to visible parts of your application and hence must cause repainting the components in question. Basically your paintComponent method
causes a repaint every time it is called effectively creating an endless loop and
is very heavyweight because it allocates expensive resources.
Both of these points are pretty bad ideas. Your paintComponent method should do just what the name suggests, i.e. painting the component. All actions that cause a repaint (changing icons or text, adding or removing components from the tree etc.) must not occur in it.
See also:
The API documentation on paintComponent(Graphics)
Painting in AWT and Swing
EDIT: When you want to resize components dependent on the size of other components create a ComponentListener and add it to the component you want to depend on by calling addComponentListener(ComponentListener). The ComponentListener instance will then have its componentResized(ComponentEvent) method called whenever the size changes.

Image only paints within original bounds

I want to animate several jpgs in a JFrame, I'll show you some extracts:
My class constructor that extends JFrame
super(title);
setLayout(null);
setResizable(false);
setSize(Settings.windowWidth, Settings.windowHeight);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
My class constructor that extends JPanel
i = new ImageIcon(image).getImage();
setSize(i.getWidth(this),i.getHeight(this));
setBounds(x, y, i.getWidth(this), i.getHeight(this));
The overwritten method
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(i, getX(), getY(), null);
}
Yes, I know null layout isn't preferrable, but unless you have a better idea for absolute positioning I'll stick with it for now.
Above code does paint the image, starting at (x,y), but not completely.
For 50 and 100 it shows this:
Which is pretty much: It only paints the image within a 256x256 box (image dimensions) from 0,0, no matter where it has been relocated to.
Any advice, help, solutions, suggestions?
If you need more code, ask me, just don't feel like putting everything around it in here, too ;)
There is no need for custom painting:
Add the ImageIcon to a JLabel and add the JLabel to a JPanel
Change the location of the label on the panel when you want to animate it.
Or, if you do custom painting then there is no need for a null layout.
You override the getPreferredSize() method of the JPanel and add your panel to the frame.
Then in the paintComponent() method you can paint the image where every you want withing the bounds of the preferred size that you set.
My gut feeling is you don't understand how component painting actually works...
First, you do this...
i = new ImageIcon(image).getImage();
setSize(i.getWidth(this),i.getHeight(this));
setBounds(x, y, i.getWidth(this), i.getHeight(this));
Then you do this...
g.drawImage(i, getX(), getY(), null);
which seems to be painting the image at a offset position from the components origin, but since the component is sized to match the size of the image, the image is cropped at the component boundaries.
When a component is painted, the Graphics context's origin is set to the components location, meaning that 0x0 is now the components top/left corner.
You can test this by using setBorder(new LineBorder(Color.RED)), which will show you the physical bounds of the component
In your case, something like
g.drawImage(i, 0, 0, this);
In your case, you should be moving the component not the image.
Personally, I'd add the JPanel to the JFrame using a BorderLayout, then you can simply move the image anywhere within the context of the component itself. Remember to override getPreferredSize to return an appropriate size for your purposes so the frame can be packed around it more effectively.
It's tricky to do animation with components (not impossible, there's just a lot to take into account), generally it's just easier to paint directly to a canvas like a JPanel, but that's me
See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works

Painting over the top of components in Swing?

I have a JPanel added to a JViewport, and the panel has several other panels added to it. I'm trying to implement a dragging selection, where you can select more than one component by dragging the mouse. The only problem I'm facing is that the selection rectangle is being painted behind the components added to the main JPanel. How can I paint over the top of them?
My structure is as follows: JFrame -> ContentPane -> JLayeredPane -> JScrollPane -> JPanel -> JPanel [].
Design draft for college assignment:
As you can see, the rectangle is behind the other panels.
This is what I'm already doing (on a much simpler level obviously), and Swing paints the rectangle underneath the components added to it.
This is one case where you should override the paint() method of the panel and not the paintComponent() method. Then the custom painting will be done AFTER all the child components have been painted.
Use a Layered Pane:
http://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html
This allows you to create overlapping components.
Use a glass pane to handle the drag painting, and possibly events as well:
http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane
hot really sure what do you really needed and final effect, maybe is there two another ways painting to
1) GlassPane
2) Viewport
you can put that together, carrefully Insets to the visible Rectanle
Without seeing your actual code, it is difficult to say what you are doing wrong. However, I can still say what I would do:
Create a JPanel that represents the whole area where you want to draw, which — of course — contains every component.
Override that panel its paintComponents(Graphics) like this (EDITED, notice the s is now the last character from the method name):
#Override
public void paintComponents(Graphics g)
{ // ^
super.paintComponents(g);
// Draw your selection rectangle:
g.setColor(Color.RED);
g.drawRectangle(selectionRectangle);
}
Okay, this is what I've decided to do in the end:
I'm not sure if this is the best way to do it, but it seems to work okay.
Note: Using MigLayout.
In the constructor of the JPanel lying underneath the colored blocks.
...
this.add(new JPanel() {
#Override
public boolean isOpaque() {
return false;
}
#Override
public void paintComponent(Graphics g) {
if (dragShape != null) {
g.setColor(Colors.SECONDARY);
g.setStroke(new BasicStroke(2));
g.draw(dragShape);
}
}
}, "pos 0 0, width 100%, height 100%", 0);
...
Custom painting on top of Swing components is facilitated by JLayeredPane. This article describes an abstract base class that facilitates overpainting specific areas (like selection rectangles or component bounds).

Java2d: JPanel set background color not working

I have the code shown below:
public VizCanvas(){
{
this.setBackground(Color.black);
this.setSize(400,400);
}
}
It worked fine and displays the panel in black background. But when I implement the paint method, which does nothing, the color changes to default color i.e gray.
I tried to set graphics.setColor() but it didn't help.
You need to do a fill of the canvas to your background colour in the painting method. Something along the lines of:
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
After that, draw whatever you need to. You could also try calling super.paint(g) in the paint method instead before doing anything.
Custom painting should be done by overriding the paintComponent() method, NOT the paint() method. Then all you do is invoke super.paintComponent() to get the background painted.
Setting the size of the component does nothing. The layout manager will override the size. You should be setting the preferred size or override the getPreferredSize() method.
Read the Swing tutorial for Swing basics. There are sections on "custom painting" and "using layout managers".

Categories

Resources