【问题标题】:Swing transparent background not being repainted摆动透明背景没有被重绘
【发布时间】:2015-02-08 13:59:09
【问题描述】:

我在 Swing 中使用透明背景时遇到问题。 由于 Swing 没有重新绘制更改的区域,因此产生了很多人工制品。

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

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

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

  1. 将透明颜色设置为背景的非透明组件(右侧 txt 字段)

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

不想想做的事:

  • 使用计时器自动重绘框架(超级糟糕)
  • 重写paintComponent 方法(它确实有效,但真的很糟糕)

我在 Win7 x64 上运行

这是我的 SSCCEEE:

更新 1:使用 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


    【解决方案1】:

    使用透明背景违反了 Swings 的绘画规则。基本上,当组件不透明时,您承诺绘制组件的背景。但是因为背景是透明的,所以没有什么可以画的。

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

    【讨论】:

    • 为提供链接点赞。我更新了我的问题,因为我认为没有理由不应该在非透明组件上绘制背景。
    • @pmkrefeld,链接解释了......并给出了解决方案。
    • 因为除了更改 JDK 定义之外,这实际上是最好的方法,我会接受这个答案。
    【解决方案2】:

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

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

    我不知道这是否就是纠正你的行为所需要的全部,但它在我的 (OS X) 上已经做到了。

    【讨论】:

    • 不幸的是,它对我没有影响。我应该提到我在 Java 6 上运行它(我没有 Lambdas :))。我将尝试使用 JDK8,希望它不会修复它。 JDK 错误是最糟糕的。
    【解决方案3】:

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

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

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

    【讨论】:

    • 我的实际代码在 EDT 上运行,我忘了在 SSCCE 中实现它。我已更新 SSCCE 以在 EDT 上运行,但仍未解决问题。
    • 只是为了清楚您是在 Java6 上运行此代码吗?如果是,升级到 Java7(或 8)是否可以解决此问题?
    • 不,幸好没有。如果 JDK6 中存在 Swing 错误,我会很高兴
    【解决方案4】:

    你应该在有问题的组件上使用setOpaque(false)并且对所有的父母都这样做

    例如,如果您在 JScrollPane 'scrollPane' 中有一个 JList 'jList',整个内容都在 JPanel 'jPanel' 中,您应该使用:

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

    是的,如果您有JScrollPane,您也应该将其视口的不透明度设置为 false。

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

    【讨论】:

      猜你喜欢
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多