透明背景JFrame Linux上的动画

时间:2015-07-09 20:30:08

标签: java linux background jframe transparent

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

下面的代码展示了我想要实现的目标 - 只需复制&粘贴它。我只是想让小矩形在屏幕上移动而不留痕迹。

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()

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

3 个答案:

答案 0 :(得分:3)

供参考,这是一个最小complete example,适合跨平台测试。注意

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

  • 应在event dispatch thread构建和操作Swing GUI对象。

  • 使用在事件派发线程上运行的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);
    }
}

答案 1 :(得分: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();
            }
        }
    });

}

}

答案 2 :(得分:2)

基本上这个问题与操作系统有关。适用于Windows的功能不适用于Linux,反之亦然。

出于某种原因,Linux在设置BufferStrategy时仅允许每像素透明动画。但是,此解决方案在Windows上失败。因此,我提出了以下代码,该代码根据操作系统选择正确的算法:

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 x64。请亲自试用这个代码,看看它是否适合您。我自己没有Mac,所以如果有人愿意为我测试,我会非常感激。如果它对任何人都不起作用,请告诉我。

这是你应该看到的:

enter image description here