半透明 JPanel 不清除背景/在 Linux 中显示背景工件 [英] Translucent JPanel not clearing background / showing background artifacts in Linux

查看:24
本文介绍了半透明 JPanel 不清除背景/在 Linux 中显示背景工件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在开发一个应用程序,该应用程序需要选择屏幕区域的功能.我想出了创建一个透明的、未装饰的全屏 JFrame,并在其中添加一个半透明、非不透明的 JPanel,其中绘制了半透明的深色背景和选区.

I am currently in the process of developing an app, that needs the functionality to select screen area. I've come up with creating a transparent, undecorated, fullscreen JFrame, and adding a translucent, non-opaque JPanel inside of it, where a half-translucent dark background, as well as the selection is painted.

虽然这个想法(和代码)在 Windows 上运行良好,但在 linux 上却不是同一个故事,在调用 repaint() 时,JPanel 的背景似乎没有被清除(即使我告诉它通过各种方法) - 每次重绘方法时,背景和组件都会变得越来越暗,等等.

And while the idea (and the code) runs fine on Windows, its not the same story on linux, where the background of the JPanel does not seem to be cleared upon calling repaint() (even though i tell it to via various methods) - upon each repaint method, the background and the component get darker and darker, etc.

这是MVCE:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ExampleFrame extends JFrame{


    private ExamplePanel selectionPane;

    public ExampleFrame(){
        this.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {

            }

            @Override
            public void keyPressed(KeyEvent e) {

            }

            @Override
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
                    ExampleFrame.this.dispatchEvent(new WindowEvent(ExampleFrame.this, WindowEvent.WINDOW_CLOSING));
                }
            }
        });


        this.setExtendedState(JFrame.MAXIMIZED_BOTH);

        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        this.setSize(screenSize);

        this.setUndecorated(true);

        this.setBackground(new Color(255, 255, 255, 0));

        populate();

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setType(Window.Type.UTILITY);
        this.setVisible(true);
    }

    private void populate(){
        this.selectionPane = new ExamplePanel();
        this.setContentPane(selectionPane);
    }

    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ExampleFrame();
            }
        });
    }

    public static class ExamplePanel extends JPanel{

        private static Color bg = new Color(0,0,0,0.5f);

        private int sx = -1, sy = -1, ex = -1, ey = -1;

        public ExamplePanel(){

            MouseAdapter mouseAdapter = new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    sx = sy = ex = ey = -1;

                    sx = e.getX();
                    sy = e.getY();
                    repaint();
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    ex = e.getX();
                    ey = e.getY();
                    repaint();
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    ex = e.getX();
                    ey = e.getY();
                    repaint();
                }
            };

            this.addMouseListener(mouseAdapter);
            this.addMouseMotionListener(mouseAdapter);

            this.setDoubleBuffered(false);
            this.setOpaque(false);
            this.setBackground(bg);
        }

        @Override
        public void paintComponent(Graphics g){
            Graphics2D g2 = (Graphics2D)g.create();

            g2.setComposite(AlphaComposite.Clear);
            g2.setBackground(new Color(255, 255, 255, 0));
            g2.fillRect(0, 0, getWidth(), getHeight());
            //g2.clearRect(0, 0, getWidth(), getHeight()); //neither of them work

            g2.setComposite(AlphaComposite.Src.derive(.5f));
            g2.setPaint(getBackground());
            g2.fillRect(0, 0, getWidth(), getHeight());

            g2.setComposite(AlphaComposite.Src.derive(1f));
            g2.setPaint(Color.WHITE);
            g2.drawString("Press Escape to exit", 10, 20);

            if(!(sx == -1 || sy == -1 || ex == -1 || ey == -1)){

                int asx = Math.min(sx, ex);
                int asy = Math.min(sy, ey);

                int w = Math.abs(ex - sx);
                int h = Math.abs(ey - sy);

                g2.setComposite(AlphaComposite.Src);
                g2.setPaint(new Color(255, 255, 255, 0));
                g2.fillRect(asx, asy, w, h);

                g2.setPaint(new Color(0, 0, 0, 1));
                g2.fillRect(asx, asy, w, h);

                g2.setComposite(AlphaComposite.SrcOver);
                g2.setStroke(new BasicStroke(2));
                g2.setPaint(new Color(1, 1, 1, 0.15f));
                g2.drawRect(asx-1,asy-1, w+2, h+2);
            }
        }
    }

}

关于什么可能导致这种情况的任何想法?或者这可能是 linux 上的 Java 错误?我已经在 Windows 10、Ubuntu 14.04 LTS 以及运行 KDE gui 的未知版本的 Arch Linux 下对此进行了测试(由朋友测试)

Any ideas as to what might cause this? Or maybe this is a bug with Java on linux? I had tested this under Windows 10, and Ubuntu 14.04 LTS as well as unknown version of Arch Linux running with KDE gui (tested by a friend)

编辑:也在 OSX (Yosemite & El capitalan) 下进行了测试,两者都运行良好.

EDIT: also tested under OSX (Yosemite & El capitan), both worked fine.

推荐答案

this.setBackground(new Color(255, 255, 255, 0));

如果你想要一个完全透明的组件,那么只需使用:

If you want a component completely transparent then just use:

component.setOpaque( false );

这告诉 Swing 查找父组件并首先对其进行绘制,这样您就不会得到绘制工件.

This tells Swing to look for the parent component and paint it first so you don't get the painting artifacts.

private static Color bg = new Color(0,0,0,0.5f);

如果您想要半透明背景,则需要进行自定义编码,因为 Swing 不支持此功能.

If you want semi-transparent backgrounds then need to do custom coding since Swing doesn't support this.

查看具有透明度的背景,了解更多信息这个主题和几个解决方案.

Check out Backgrounds With Transparency for more information on this topic and a couple of solutions.

一种是使用以下代码进行您自己的自定义绘画:

One is to do your own custom painting with code like:

JPanel panel = new JPanel()
{
    protected void paintComponent(Graphics g)
    {
        g.setColor( getBackground() );
        g.fillRect(0, 0, getWidth(), getHeight());
        super.paintComponent(g);
    }
};

另一种解决方案是一个可重用的类,它可以与任何组件一起使用,因此您无需自定义每个组件.panel.setOpaque(false);//将首先绘制父级的背景panel.setBackground(新颜色(255, 0, 0, 20));frame.add(面板);

The other solution is a reusable class that can be used with any component so you don't need to customize every component. panel.setOpaque(false); // background of parent will be painted first panel.setBackground( new Color(255, 0, 0, 20) ); frame.add(panel);

这篇关于半透明 JPanel 不清除背景/在 Linux 中显示背景工件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆