簡體   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