繁体   English   中英

摇摆的透明背景没有被重新粉刷

[英]Swing transparent background not being repainted

我在Swing中使用透明背景时遇到问题。 由于摇摆不重涂变化的区域,因此产生了许多人工制品。

越野车

据我所知,有两种现成的使用透明背景的方法:

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

问题 :背景的透明部分永远不会刷新->伪像。

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

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

不想做的事:

  • 使用计时器自动重新绘制框架(非常糟糕)
  • 重写paintComponent方法(这确实有效,但是确实很糟糕)

我在Win7 x64上运行

Aaaand这是我的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的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);
}

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

通过使用透明背景,您正在打破Swings绘画规则。 基本上,当组件不透明时,您保证会绘制组件的背景。 但是因为背景是透明的,所以不需要绘画。

请查看“ 透明背景”,以获取更多信息和几个简单的解决方案。

您应该遵守Swing的线程策略,并在GUI线程上初始化GUI:

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

我不能说这是否是纠正您这一方面行为所需要的全部,但它只是在我的OS X上完成的。

我不能对此施加足够的压力,我看到很多人没有这样做,而确保Swing的正确行为至关重要。 所有GUI实例必须在EDT(事件调度线程)上运行

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

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

您应该在有问题的组件上使用setOpaque(false)并对所有父组件执行相同的操作

举例来说,如果你有一个JList一个内部“JList的JScrollPane “滚动窗格”,整个事情是一个内部JPanel “的JPanel”,你应该使用:

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

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

这样可以防止在具有透明背景的组件上出现绘画问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM