I have a problem with drawing. I have a frame with one button. Using the mouse, I draw a transculent rectangle. But I have a small problem, because when drawing this rectangle, it is drawing behind the button and I want this rectangle to be over the button.
This is a screenshot:
And this is the code:
package draw;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
public class Selection extends JPanel
implements ChangeListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final int WIDE = 640;
private static final int HIGH = 640;
private List<Node> nodes = new ArrayList<Node>();
private Point mousePt = new Point(WIDE / 2, HIGH / 2);
private Rectangle mouseRect = new Rectangle();
private boolean selecting = false;
public static void main(String[] args) throws Exception {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("GraphPanel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Selection gp = new Selection();
f.add(new JScrollPane(gp), BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
});
}
Selection() {
JButton but=new JButton("Button");
add(but);
this.setPreferredSize(new Dimension(WIDE, HIGH));
this.addMouseListener(new MouseHandler());
this.addMouseMotionListener(new MouseMotionHandler());
}
@Override
public void paintComponent(Graphics g) {
g.setColor(new Color(0x00f0f0f0));
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLACK);
((Graphics2D) g).setComposite(AlphaComposite.getInstance(rule, alpha));
g.fillRect(mouseRect.x, mouseRect.y,
mouseRect.width, mouseRect.height);
g.drawRect(mouseRect.x, mouseRect.y,
mouseRect.width, mouseRect.height);
}
int rule = AlphaComposite.SRC_OVER;
float alpha = 0.85F;
private class MouseHandler extends MouseAdapter {
@Override
public void mouseReleased(MouseEvent e) {
selecting = false;
mouseRect.setBounds(0, 0, 0, 0);
if (e.isPopupTrigger()) {
}
e.getComponent().repaint();
}
@Override
public void mousePressed(MouseEvent e) {
mousePt = e.getPoint();
Node.selectNone(nodes);
selecting = true;
e.getComponent().repaint();
}
}
private class MouseMotionHandler extends MouseMotionAdapter {
@Override
public void mouseDragged(MouseEvent e) {
if (selecting) {
mouseRect.setBounds(
Math.min(mousePt.x, e.getX()),
Math.min(mousePt.y, e.getY()),
Math.abs(mousePt.x - e.getX()),
Math.abs(mousePt.y - e.getY()));
}
e.getComponent().repaint();
}
}
/** A Node represents a node in a graph. */
private static class Node {
private Color color;
private boolean selected = false;
private Rectangle b = new Rectangle();
/** Draw this node. */
public void draw(Graphics g) {
g.setColor(this.color);
if (selected) {
g.setColor(Color.darkGray);
g.drawRect(b.x, b.y, b.width, b.height);
}
}
/** Mark this node as slected. */
public void setSelected(boolean selected) {
this.selected = selected;
}
/** Select no nodes. */
public static void selectNone(List<Node> list) {
for (Node n : list) {
n.setSelected(false);
}
}
}
@Override
public void stateChanged(ChangeEvent arg0) {
// TODO Auto-generated method stub
}
}
How can I solve this problem?
Normally custom painting is done by overriding the paintComponent() method. So the painting order is to paint the component and then the children are painted. So the button is painted on top of the rectangle.
In this case you want the rectangle to be painted after the children so you can do this by overriding the paint() method. Now the panel and its children will be painted. Then your rectangle will be painted so it gets painted on top of the button.
So your basic code should be:
@Override
public void paint(Graphics g)
{
super.paint(g); // added this
g.setColor(new Color(0x00f0f0f0));
// g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLACK);
((Graphics2D) g).setComposite(AlphaComposite.getInstance(rule, alpha));
g.fillRect(mouseRect.x, mouseRect.y, mouseRect.width, mouseRect.height);
g.drawRect(mouseRect.x, mouseRect.y, mouseRect.width, mouseRect.height);
}