Gergely Gergely - 3 months ago 5
Java Question

Components render an unusal way

I have a custom

JPanel
class and I want it to paint several rectangles and texts in front of it's child components. I have overridden this method:

public void paint(Graphics g){
g = getComponentGraphics(g);
super.paint(g);
//paint my custom content
}


super.paint
calls
paintChildren
whitch draws the child components. But the child components appear in front of my custom content, and they also sometimes Z fight with each other.

I'm absolutely clueless about what might be causing this.

NOTE: I use
setComponentZOrder
in my code, and my
JPanel
takes place in a
JScrollPane
.

EDIT: The components ZFight even if I never call the setComponentZOrder method.

EDIT 2:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;

import javax.accessibility.Accessible;
import javax.accessibility.AccessibleSelection;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example extends JPanel{
private static final long serialVersionUID = 1L;
public static void main(String[] atgs){
JFrame frame = new JFrame("ZFightingExample");
frame.setSize(new Dimension(500,500));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ExamplePanel panel = new ExamplePanel();
frame.add(panel);
Example a = new Example(new Rectangle(5,5,50,50)),
b = new Example(new Rectangle(40,40,50,50));
panel.add(a);
panel.add(b);
frame.setVisible(true);
}
public Example(Rectangle bounds){
super();
setBounds(bounds);
}
public void paint(Graphics g){
super.setBackground(Color.GREEN);
g.fillRect(0, 0, getWidth()-1, getHeight()-1);
super.paint(g);
g.setColor(Color.BLACK);
g.drawRect(0, 0, getWidth()-1, getHeight()-1);
}
}
class ExamplePanel extends JPanel{
private static final long serialVersionUID = 1L;
public ExamplePanel(){
super(null);
accessibleContext = new Accessiblecontext();
};
protected class Accessiblecontext extends AccessibleJPanel implements AccessibleSelection{
private static final long serialVersionUID = 1L;
public int getAccessibleSelectionCount() {return 2;}
public Accessible getAccessibleSelection(int i) {return (Accessible)getComponent(i);}
public boolean isAccessibleChildSelected(int i) {return true;}
public void addAccessibleSelection(int i) {}
public void removeAccessibleSelection(int i) {}
public void clearAccessibleSelection() {}
public void selectAllAccessibleSelection() {}
}
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.BLUE);//Should be in front of the Green boxes...
g.drawRect(10, 10, 75, 75);
}
}

Answer

I want it to paint several rectangles and texts in front of it's child components.

Normally you override paintCompnent() to do custom painting.

The question is what does "in front" mean to you? If it means what I think it means then you need to do the painting after the child components have been painted. So you basic approach to override paint() is correct.

public void paint(Graphics g){
    g = getComponentGraphics(g);
    super.paint(g);
    //paint my custom content
}

The problem with the above code is that you don't use the Graphics object passed to the painting method. So your code should be:

public void paint(Graphics g)
{
    //g = getComponentGraphics(g);
    super.paint(g);  // use the Graphics object passed to the method

    //paint my custom content

    g.drawRect(10, 10, 20, 20);
}

I use setComponentZOrder in my code,

Why are you playing with ZOrder?

Edit:

g.setColor(Color.BLUE);//Should be in front of the Green boxes...

As I first stated in my answer, normally (99% of the time) custom painting is done by overriding the paintComponent() method of the panel.

The problem is with the Example class:

  1. override paintComponent() not paint()
  2. the first statement when you override a painting method should be super.???.
  3. don't set properties of the class in the painting method.

So the code might look something like:

public Example(Rectangle bounds){
    super();
    setBounds(bounds);
    setBackground(Color.GREEN);
}
public void paintComponent(Graphics g){
    super.paintComponent(g);
    g.setColor(getBackground());
    g.fillRect(0, 0, getWidth()-1, getHeight()-1);
    g.setColor(Color.BLACK);
    g.drawRect(0, 0, getWidth()-1, getHeight()-1);
}

Note you don't event need to do any custom painting with the Example class. Instead your code could be something like:

ExamplePanel panel = new ExamplePanel();
panel.setLayout( null ); // now you set the size/location of any component you add to the panel

JPanel example1 = new JPanel();
example1.setBackground( Color.GREEN );
example1.setBorder( new LineBorder(Color.BLACK) );
example1.setBounds( new Rectangle(....) );

panel.add(example1);

Also, another solution for the ExamplePanel class might be to use a JLayer. The JLayer class allows you to add all kinds of fancy decorations to a component. Check out the Swing tutorial on How to Decorate Components With The JLayer Class.