Search code examples
javaswingjbuttonpaintcomponent

Java Swing and drawing problem


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?


Solution

  • 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);
        }