简体   繁体   English

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

[英]Swing transparent background not being repainted

I have a problem using transparent backgrounds in Swing. 我在Swing中使用透明背景时遇到问题。 There are a lot of artefacts produced as swing is not repainting changed regions. 由于摇摆不重涂变化的区域,因此产生了许多人工制品。

越野车

As far as I can tell there are 2 out-of-the-box ways to use transparent backgrounds: 据我所知,有两种现成的使用透明背景的方法:

  1. an opaque component with transparent color set as background (left txt field) 具有透明颜色的不透明组件设置为背景(左侧txt字段)

Problem : the transparent part of the background is never refreshed -> Artefacts. 问题 :背景的透明部分永远不会刷新->伪像。

  1. an non-opaque component with transparent color set as background (right txt field) 非透明组件,其透明颜色设置为背景(右侧txt字段)

Problem : background is not being drawn at all. 问题 :根本没有绘制背景。

What I do not want to do: 不想做的事:

  • to use timers to auto repaint the frame (super awful) 使用计时器自动重新绘制框架(非常糟糕)
  • to override paintComponent method (which actually works, but is really really awful) 重写paintComponent方法(这确实有效,但是确实很糟糕)

I am running on Win7 x64 我在Win7 x64上运行

Aaaand here is my SSCCEEE: Aaaand这是我的SSCCEEE:

Update 1: init with invokeLater (still won't work) 更新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();
    }
}

Update 2 更新2

As some of you noticed, it seems Swing that swing is unable to paint transparent backgrounds. 如您所知,Swing的Swing似乎无法绘制透明背景。 But it is not (yet) clear to me why, I searched for the piece of code responsible for drawing the background of the component and have found the following code in ComponentUI.java : 但是我还不清楚为什么,我搜索了负责绘制组件背景的代码,并在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);
}

As you can see, it assumes that if a component is not opaque the background doesn't need to be repainted. 如您所见,它假定如果组件不是不透明的,则不需要重新绘制背景。 I say that this is a very vague assumption. 我说这是一个非常模糊的假设。

I would propose following implementation: 我建议以下实施:

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

I simply check if the background was set at all when the component is not opaque. 我只是检查组件不透明时是否设置了背景。 This simple addition would allow us to use transparent backgrounds in swing. 这种简单的添加将使我们能够在秋千中使用透明背景。 At least I do not know any reasons why it should not be done that way. 至少我不知道为什么不应该这样做。

By using a transparent background you are breaking Swings painting rules. 通过使用透明背景,您正在打破Swings绘画规则。 Basically when the component is opaque you promise to paint the background of the component. 基本上,当组件不透明时,您保证会绘制组件的背景。 But because the background is transparent there is nothing to paint. 但是因为背景是透明的,所以不需要绘画。

Check out Backgrounds With Transparency for more information and a couple of simple solutions. 请查看“ 透明背景”,以获取更多信息和几个简单的解决方案。

You should respect Swing's threading policy and have the GUI initialized on the GUI thread: 您应该遵守Swing的线程策略,并在GUI线程上初始化GUI:

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

I can't tell whether this is all it will take to correct the behavior on your side, but it has done just that on mine (OS X). 我不能说这是否是纠正您这一方面行为所需要的全部,但它只是在我的OS X上完成的。

I cannot stress this enough, I see a ton of people not doing this while it is vital to ensure correct behavior from Swing; 我不能对此施加足够的压力,我看到很多人没有这样做,而确保Swing的正确行为至关重要。 ALL GUI instances must run on the EDT(Event Dispatch Thread) 所有GUI实例必须在EDT(事件调度线程)上运行

Please read the below article and adjust your code and report back with the effects. 请阅读以下文章并调整您的代码,并报告有关效果。

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

You should use setOpaque(false) on the component that has a problem, and do the same with all the parents ! 您应该在有问题的组件上使用setOpaque(false)并对所有父组件执行相同的操作

For example, if you have a JList 'jList' inside a JScrollPane 'scrollPane', the whole thing being inside a JPanel 'jPanel', you should use : 举例来说,如果你有一个JList一个内部“JList的JScrollPane “滚动窗格”,整个事情是一个内部JPanel “的JPanel”,你应该使用:

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

And yes, if you have a JScrollPane , you should set its viewport's opacity to false as well. 是的,如果您有JScrollPane ,则还应该将其视口的不透明度设置为false。

This will prevent painting problems on your components with transparent backgrounds. 这样可以防止在具有透明背景的组件上出现绘画问题。

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

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