半透明JPanel不清除Linux中的背景/显示背景工件

时间:2016-01-29 21:33:16

标签: java linux swing

我目前正在开发应用程序,需要选择屏幕区域的功能。我想出了一个透明的,未修饰的全屏JFrame,并在其中添加了半透明的,不透明的JPanel,其中半透明的黑色背景以及选择被绘制。

虽然这个想法(和代码)在Windows上运行良好,但它在linux上的故事并不相同,在调用repaint()时,JPanel的背景似乎没有被清除(尽管我告诉它通过各种方法) - 每个重绘方法,背景和组件变得更暗更暗等

这是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(由朋友测试)中进行了测试

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

3 个答案:

答案 0 :(得分:3)

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

如果您希望组件完全透明,请使用:

component.setOpaque( false );

这告诉Swing寻找父组件并先绘制它,这样你就不会得到绘画工件。

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

如果你想要半透明背景,那么需要自定义编码,因为Swing不支持这个。

查看Backgrounds With Transparency以获取有关此主题和一些解决方案的更多信息。

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

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

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

答案 1 :(得分:2)

如果无法复制问题,很难知道问题的确切原因。代码中有许多值得关注的领域...

  • 不通过调用super.paintComponent
  • 来表彰油漆调用链
  • 使用setDoubleBuffered(false)
  • this.setBackground(bg);上使用JPanel并将基于alpha的颜色传递给它
  • 广泛使用AlphaComposite并谨慎使用以尝试清除Graphics背景

基本行动方针是简化绘画流程,直到您能够确定导致问题的行动或行动组合为止。

或采取另一种方法。您可以考虑仅使用AlphaComposite并减去要从中公开的区域,而不是使用不同Area设置的组合....

Cut

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.geom.Area;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

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

        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.setOpaque(false);
        }

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

            Area area = new Area(new Rectangle(0, 0, getWidth(), getHeight()));

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

                area.subtract(new Area(new Rectangle(asx - 1, asy - 1, w + 2, h + 2)));
            }
            g2.setComposite(AlphaComposite.Src.derive(.25f));
            g2.setPaint(bg);
            g2.fill(area);

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

}

答案 2 :(得分:0)

如果要清除背景,请务必致电super.paintComponent()

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