2015-07-09 189 views
9

我想为Frame(或JFrame)创建一个完全透明的背景并让它显示透明的动画。我设法让它在Windows 7 x64下工作,但是相同的代码不能在我的Linux上运行(Lubuntu x64 15.04)。透明背景JFrame Linux上的动画

下面的代码显示了我试图实现 - 只需复制&粘贴它。我只想让小矩形在屏幕上移动而不留下踪迹。

static int a = 0; 

public static void main(String[] args) { 
    JFrame f = new JFrame(); 
    f.setUndecorated(true); 
    f.setBackground(new Color(0, 0, 0, 0)); 
    f.setVisible(true); 
    f.setSize(512, 512); 
    f.add(new JPanel() { 
     @Override 
     public void paintComponent(Graphics gr) { 
      Graphics2D g = (Graphics2D)gr; 
      g.setBackground(new Color(0, 0, 0, 0)); 
      g.clearRect(0, 0, 512, 512); 
      g.drawRect(a, a++, 2, 2); 
     } 
    }); 

    while(true) { 
     try { 
      Thread.sleep(30); 
     } catch(InterruptedException e) { 
      e.printStackTrace(); 
     } 
     f.repaint(); 
    } 
} 

我想实现(如在Windows中所示)和我所得到的与Lubuntu 15.04:

Desired Animation                 Lubuntu Animation

我只是想看看小方块就像Windows 7上显示的那样移动 - 我不想看到踪迹。

请不要给我Oracle的透明度和窗口文档的链接 - 我已经完成了三次。

我已经试过:

  • 的Graphics2D的透明空间 '那么copyArea()'。 (这曾经工作AFAIK,但不再做)
  • 玻璃面板
  • 的AlphaComposite
  • setPaint()

请请只是测试你的想法/代码第一。很多“这应该工作”的东西,我已经尝试过,似乎并不......所有的帮助,非常感谢。

+0

多小时,小时后我发现它:这是一个背缓冲区的问题。我找到了解决这个问题的方法,但我现在没有太多时间,所以我会在今天晚些时候发布。仍然需要在Windows上测试它。我的解决方案似乎有点闪烁,所以我可能会看看我是否也可以解决这个问题。无论如何,我会非常感谢新解决方案的测试帮助,因为我只有Windows 7 x64和Lubuntu 15.04。多谢你们。 – Roland

+0

不能等待答案,我会尝试在我的电脑上:D – JetStream

+0

@JStStream我在下面发布了一个答案。它适用于Linux和Windows 7对我来说,但我没有一个Mac,所以我不能测试那个... – Roland

回答

2

基本上这个问题是OS相关的。对Windows有效的东西不适用于Linux,反之亦然。

由于某些原因,Linux在设置BufferStrategy时只允许动画每像素透明度。但是,此解决方案在Windows上失败。因此,我想出了下面的代码,其拾取基于OS的正确算法:

static int a = 0; 

public static void main(String[] args) { 
    JFrame f = new JFrame(); 
    JPanel p = new JPanel() { 
     @Override 
     public void paintComponent(Graphics g) { 
      Graphics2D g2d = (Graphics2D) g; 
      g2d.setBackground(new Color(255, 255, 255, 0)); 
      g2d.clearRect(0, 0, f.getWidth(), f.getHeight()); 
      g2d.drawRect(a, a++, 2, 2); 
     } 
    }; 
    f.add(p); 
    f.setUndecorated(true); 
    f.setBackground(new Color(255, 255, 255, 0)); 
    f.setSize(512, 512); 
    f.setVisible(true); 
    f.createBufferStrategy(2); 

    BufferStrategy bs = f.getBufferStrategy(); 
    while (true) { 
     try { 
      Thread.sleep(33); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     if (System.getProperty("os.name").contains("indows ")) { 
      p.repaint(); 
     } else { 
      Graphics g = null; 
      do { 
       try { 
        g = bs.getDrawGraphics(); 
        p.update(g); 
       } finally { 
        g.dispose(); 
       } 
       bs.show(); 
      } while (bs.contentsLost()); 
      Toolkit.getDefaultToolkit().sync(); 
     } 
    } 
} 

此代码为我的Windows 7 x64和我的Lubuntu 15.04 64。请自行尝试此代码,看看它是否适用于您。我自己不拥有Mac,所以如果有人愿意为我测试它,我会非常感激。如果它不适合任何人,请告诉我。

这是你应该看到:

enter image description here

+0

适用于带有'.contains(“Mac”)'的Mac OS X,但请参阅[*初始线程*](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html)。 – trashgod

+0

@trashgod所以Mac也需要调用p.repaint()? – Roland

+0

是的,AFAIK;我从'javax.swing.Timer'中调用'repaint()',它调度EDT上的可运行函数,在我的[例子](http: /stackoverflow.com/a/31328464/230513)。 – trashgod

2

如果我们扩展JFrame,将undecorated设置为true,并覆盖paint,我们可以制作一个透明的JFrame。

试试这个,

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Point; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.io.IOException; 
import java.net.MalformedURLException; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.BorderFactory; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class TestTransparentFrame { 

private class PaintPanel extends JPanel { 
    private List<Point> points = new ArrayList<Point>(); 

    public PaintPanel() { 
     setOpaque(false); 
     MouseAdapter adapter = new MouseAdapter() { 
      @Override 
      public void mouseClicked(MouseEvent e) { 
       points.clear(); 
       repaint(); 
      } 

      @Override 
      public void mouseMoved(MouseEvent e) { 
       points.add(e.getPoint()); 
       repaint(); 
      } 
     }; 
     addMouseListener(adapter); 
     addMouseMotionListener(adapter); 
     setBorder(BorderFactory.createLineBorder(Color.GREEN)); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     if (points.size() > 1) { 
      g.setColor(Color.RED); 
      Point p1 = points.get(0); 

      for (int i = 1; i < points.size(); i++) { 
       Point p2 = points.get(i); 
       g.drawLine(p1.x, p1.y, p2.x, p2.y); 
       p1 = p2; 
      } 
     } 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(700, 500); 
    } 
} 

protected void createAndShowGUI() throws MalformedURLException, IOException { 
    JFrame frame = new JFrame("Test transparent painting"); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setUndecorated(true); 
    frame.setBackground(new Color(0, 0, 0, 50)); 
    frame.add(new PaintPanel()); 
    frame.pack(); 
    frame.setVisible(true); 
} 

public static void main(String[] args) { 
    SwingUtilities.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
      try { 
       new TestTransparentFrame().createAndShowGUI(); 
      } catch (MalformedURLException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    }); 

} 

} 
+0

Thx的答复,但我已经试过这个。如果你可以编辑你的答案并粘贴很好的工作代码。 – Roland

+0

Thx用于发布您的代码,但此特定示例不适用于我遇到的问题。移动鼠标时,我希望线条/线迹消失。问题是在重新绘制JPanel之前,JFrame没有清除它的屏幕内容。换句话说,JPanel不断绘制自己......这是我遇到的问题,但感谢您的帮助:) – Roland

3

仅供参考,这里有一个最小的complete example,适用于跨平台的测试。请注意,

  • 在某些平台上Ubuntu,一个完全透明背景不被视为opaque;一个小的非零值alpha值是一个典型的解决方法。

  • Swing GUI对象应该在event dispatch thread上构建和操纵只有

  • 使用java.swing.Timer,它运行在事件调度线程上,以调整动画的速度。

  • 当您确实想要覆盖getPreferredSize()时,请勿使用setPreferredSize()

image

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.Timer; 

/** 
* @see https://stackoverflow.com/a/31328464/230513 
*/ 
public class TransparentAnimation { 

    private static final Color tranparentBlack = new Color(0, 0, 0, 1); 

    private void display() { 
     JFrame f = new JFrame("Test"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setUndecorated(true); 
     f.setBackground(tranparentBlack); 
     f.add(new JPanel() { 
      int x, y; 
      Timer t = new Timer(10, (ActionEvent e) -> { 
       x = (x + 1) % getWidth(); 
       y = (y + 1) % getHeight(); 
       repaint(); 
      }); 

      { 
       setBackground(tranparentBlack); 
       t.start(); 
      } 

      @Override 
      public void paintComponent(Graphics g) { 
       super.paintComponent(g); 
       g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); 
       g.fillOval(x, y, 16, 16); 
      } 

      @Override 
      public Dimension getPreferredSize() { 
       return new Dimension(320, 240); 
      } 
     }); 
     f.add(new JLabel(System.getProperty("os.name") + "; v" 
      + System.getProperty("os.version")), BorderLayout.SOUTH); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new TransparentAnimation()::display); 
    } 
} 
+0

[Screenshots](http://meta.stackoverflow.com/questions/99734/how-do -i-create-a-screenshot-to-illustrations-a-post)欢迎其他平台/版本。 – trashgod

+0

Thx的答复,但这不能回答我的问题。我知道如何创建一个透明框架,我的示例代码已经完成。我想知道如何创建一个动画。我刚刚测试了我在Windows机器上发布的代码,看起来我的代码运行良好,所以出于某种原因,它不想在我的Linux上工作。不知道它是Linux,Ubuntu还是LXDE问题... – Roland

+0

@罗兰:啊,我误解了你的例子,它似乎修改了一个线程上的'a'并在另一个线程上访问它。更多上面。 – trashgod