Swing透明背景没有被重新粉刷

问题描述 投票:1回答:4

我在Swing中使用透明背景时遇到问题。由于挥杆不会重新改变变化的区域,因此产生了大量的人工制品。

据我所知,有两种开箱即用的方式可以使用透明背景:

  1. 透明色设置为背景的不透明组件(左侧文本字段)

问题:背景的透明部分永远不会刷新 - >人工制品。

  1. 一个透明颜色设置为背景的非不透明组件(右侧文本字段)

问题:根本没有绘制背景。

我不想做的事:

  • 使用计时器自动重绘框架(超级糟糕)
  • 覆盖paintComponent方法(实际上有效,但真的非常糟糕)

我在Win7 x64上运行

Aaaand在这里是我的SSCCEEE:

更新1:init与invokeLater(仍然无法工作)

public class OpacityBug {

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

    static final Color transparentBlue = new Color(0f, 1f, 0f, 0.5f); 

    JFrame frame;
    JPanel content;

    JTextField txt1;
    JTextField txt2;

    public OpacityBug() {
        initFrame();
        initContent();
    }

    void initFrame() {
        frame = new JFrame();
        frame.setSize(300, 80);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    void initContent() {
        content = new JPanel();
        content.setDoubleBuffered(true);
        content.setBackground(Color.red);
        frame.getContentPane().add(content);

        txt1 = new JTextField() {
            @Override
            public void setBorder(Border border) {
                super.setBorder(null); //nope border
            }
        };
        txt1.setText("Hi! I am Buggy!");
        txt1.setOpaque(true);
        txt1.setBackground(transparentBlue);
        content.add(txt1);

        txt2 = new JTextField() {
            @Override
            public void setBorder(Border border) {
                super.setBorder(null); //nope border
            }
        };
        txt2.setText("And I have no BG!");
        txt2.setOpaque(false);
        txt2.setBackground(transparentBlue);
        content.add(txt2);

        content.revalidate();
        content.repaint();
    }
}

更新2

正如你们中的一些人注意到的那样,Swing看起来挥杆无法画出透明的背景。但是,为什么我还没有清楚地知道为什么,我搜索了负责绘制组件背景的代码片段,并在ComponentUI.java中找到了以下代码:

public void update(Graphics g, JComponent c) {
if (c.isOpaque()) {
    g.setColor(c.getBackground());
    g.fillRect(0, 0, c.getWidth(),c.getHeight());
}
paint(g, c);
}

如您所见,它假设如果组件不是不透明的,则不需要重新绘制背景。我说这是一个非常模糊的假设。

我建议以下实施:

public void update(Graphics g, JComponent c) {
if(c.isOpaque() || (!c.isOpaque() && c.isBackgroundSet())) {
    g.setColor(c.getBackground());
    g.fillRect(0, 0, c.getWidth(), c.getHeight());
}
paint(g, c);
}

我只是检查组件是否不透明时是否设置了背景。这个简单的添加将允许我们在秋千中使用透明背景。至少我不知道为什么不应该这样做。

java swing transparency repaint
4个回答
2
投票

通过使用透明背景,您可以打破Swings绘画规则。基本上,当组件不透明时,您承诺绘制组件的背景。但由于背景是透明的,因此无需绘画。

查看Backgrounds With Transparency以获取更多信息和一些简单的解决方案。


1
投票

您应该尊重Swing的线程策略并在GUI线程上初始化GUI:

SwingUtilities.invokeLater(() -> new OpacityBug());

我无法分辨这是否只是纠正你身边的行为,但它已经完成了我的(OS X)。


1
投票

我不能强调这一点,我看到很多人没有这样做,而确保Swing的正确行为至关重要;所有GUI实例必须在EDT上运行(事件调度线程)

请阅读以下文章并调整您的代码并报告效果。

https://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html


0
投票

你应该在有问题的组件上使用setOpaque(false),并对所有父母做同样的事情!

例如,如果你在JList'scrollPane'中有一个JScrollPane'jList',整个东西都在JPanel'jPanel'里面,你应该使用:

jList.setOpaque(false);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
jPanel.setOpaque(false);

是的,如果你有一个JScrollPane,你应该将它的视口的不透明度设置为false。

这将防止具有透明背景的组件上的绘制问题。

© www.soinside.com 2019 - 2024. All rights reserved.