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

时间:2014-12-10 11:30:19

标签: java swing transparency repaint

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

buggy

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

  1. 透明色设置为背景的不透明组件(左侧txt字段)
  2. 问题:背景的透明部分永远不会刷新 - >假象。

    1. 将透明色设置为背景的非不透明组件(右侧txt字段)
    2. 问题:根本没有绘制背景。

      我做什么想做:

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

      我在Win7 x64上运行

      Aaaand在这里是我的SSCCEEE:

      使用invokeLater更新1:init(仍然无效)

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

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

4 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:0)

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

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

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

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

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