JFrame - 仅部分透明

6

我想让JFrame的一部分透明。它应该看起来像OneNote屏幕剪辑器。我基本上有一个全屏叠加的部分透明的JFrame,然后在这个JFrame里面,我想通过拖动鼠标制作一些矩形,并使这些矩形完全透明,就像这样:

---------------------------------------
|        partially transparent         |
|                                      |
|      -----------                     |
|      | fully   |                     |
|      | transp. |                     |
|      -----------                     |
----------------------------------------

我该怎么做?目前我有以下内容:
public class Overlay extends JFrame implements MouseMotionListener, MouseListener {

    private Rectangle2D.Double selection;
        private Point start;
        private Point end;

    public Overlay() {
        addMouseMotionListener(this);
        addMouseListener(this);
        setSize(Toolkit.getDefaultToolkit().getScreenSize());
        setAlwaysOnTop(true);
        setUndecorated(true);
        setOpacity(0.2f);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    @Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.clearRect(0, 0, getWidth(), getHeight());

        if (selection != null) {

            Area outside = new Area(new Rectangle2D.Double(0, 0, getWidth(), getHeight()));
            outside.subtract(new Area(selection));


            g2d.setClip(outside);               
            g2d.setColor(new Color(0.5f,0.5f,0.5f, 0.5f));
            g2d.fillRect(0, 0, getWidth(), getHeight());
        }

    @Override
    public void mousePressed(MouseEvent e) {

        start = e.getLocationOnScreen();
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        end = e.getLocationOnScreen();
        selection =  new Rectangle2D.Double(start.x, start.y, end.x - start.x, end.y - start.y);
        repaint();
    }
}

但是这种方法并不正确,因为它会多次重绘背景,导致背景变得更暗/透明度降低,并且速度非常慢... 重绘需要很长时间,而且非常明显。


1
不要覆盖paint,而是覆盖paintComponent()。如果您没有实现所有方法,请使用适配器而不是监听器。 - user1803551
你是指paintComponents()吗?JFrame中没有paintComponent()。如果我这样做,它就不再绘制任何东西,只显示JFrame :/ - Blub
2个回答

0
作为一个快速解决方案,请调用:
repaint((int) selection.x,(int) selection.y,(int) selection.width,(int) selection.height);

使用repaint()的地方,可以考虑使用其他替代方法。

当然,这种做法并不是最佳实践。


0

我终于自己解决了:

public class Overlay extends JFrame {
    private Point start = new Point();
    private Point end = new Point();

    public Overlay() {
        OverlayMouseAdapter listener = new OverlayMouseAdapter();
        addMouseMotionListener(listener);
        addMouseListener(listener);
        setSize(Toolkit.getDefaultToolkit().getScreenSize());
        setAlwaysOnTop(true);
        setUndecorated(true);
        setBackground(new Color(255, 255, 255, 180));
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;


        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR,
                    0.1f));
        g2d.setColor(new Color(0, 0, 0, 255));
        g2d.fillRect(start.x, start.y, end.x -start.x, end.y-start.y);

        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
        g2d.setColor(Color.BLACK);
        g2d.drawRect(start.x-1, start.y-1, end.x -start.x + 1, end.y-start.y+1);
    }

    private class OverlayMouseAdapter extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            start = e.getLocationOnScreen();
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            end = e.getLocationOnScreen();
            repaint();
        }
    }
}

我们可以使用AlphaComposite.CLEAR,它将从背景中移除不透明度(至少在这里是这样做的)。

1
使用适配器替换监听器。 - user1803551
顺便说一下,你的代码使得你只能将矩形向下和向右拖动。你不想允许原点成为右下角吗? - user1803551

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接