透明背景 JFrame 上的动画 Linux
Animation on Transparent-background JFrame Linux
我想为 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得到的:
我只想看到小方块像Windows 7 上显示的那样移动--我不想看到轨迹。
请不要给我 link Oracle 的透明度和 window 文档——我已经看过三次了。
我试过的:
- Graphics2D 的'copyArea()' 透明space。 (这曾经有效,但现在无效了)
- 玻璃板
- Alpha 复合
- setPaint()
请先测试一下您的 thoughts/code。很多 "this should work" 东西我已经尝试过但似乎没有...非常感谢所有帮助。
如果我们扩展 JFrame,将 undecorated 设置为 true,并重写 paint with,我们可以制作一个透明的 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();
}
}
});
}
}
作为参考,这里有一个最小的 complete example,适合跨平台测试。注意
在某些平台上,例如Ubuntu,完全透明背景不被视为opaque;一个小的非零 alpha 值是典型的解决方法。
Swing GUI 对象应该在 event dispatch thread.
上仅 构建和操作
使用在事件调度线程上运行的 java.swing.Timer
来控制动画的节奏。
当你真的想覆盖getPreferredSize()
时,不要使用setPreferredSize()
。
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
*/
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);
}
}
基本上这个问题与 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 x64。请自己试用此代码,看看它是否适合您。我自己没有 Mac,所以如果有人愿意为我测试一下,我将不胜感激。如果它对任何人都不起作用,请告诉我。
这是你应该看到的:
我想为 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得到的:
我只想看到小方块像Windows 7 上显示的那样移动--我不想看到轨迹。
请不要给我 link Oracle 的透明度和 window 文档——我已经看过三次了。
我试过的:
- Graphics2D 的'copyArea()' 透明space。 (这曾经有效,但现在无效了)
- 玻璃板
- Alpha 复合
- setPaint()
请先测试一下您的 thoughts/code。很多 "this should work" 东西我已经尝试过但似乎没有...非常感谢所有帮助。
如果我们扩展 JFrame,将 undecorated 设置为 true,并重写 paint with,我们可以制作一个透明的 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();
}
}
});
}
}
作为参考,这里有一个最小的 complete example,适合跨平台测试。注意
在某些平台上,例如Ubuntu,完全透明背景不被视为opaque;一个小的非零 alpha 值是典型的解决方法。
Swing GUI 对象应该在 event dispatch thread.
上仅 构建和操作
使用在事件调度线程上运行的
java.swing.Timer
来控制动画的节奏。当你真的想覆盖
getPreferredSize()
时,不要使用setPreferredSize()
。
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
*/
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);
}
}
基本上这个问题与 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 x64。请自己试用此代码,看看它是否适合您。我自己没有 Mac,所以如果有人愿意为我测试一下,我将不胜感激。如果它对任何人都不起作用,请告诉我。
这是你应该看到的: