半透明の JFrame を使用して Java でアニメーションを実行しようとしています。ここで、Oracle Java チュートリアルのデモ コードを変更しました。具体的には、GradientTranslucentWindowDemo です。
次のコードは、Windows XP SP3 から 8 まで、および Mac OS X Mountain Lion で、またほとんどの場合 Linux でもうまく機能します。 Linux の問題であり、私が助けを必要としているのは、アニメーションがちらつくことです。
nVidia ドライバー、Metacity、および Compiz を使用して Ubuntu Linux 12.04 LTS 64 ビットを実行しています。PERPIXEL_TRANSLUCENT は true を報告し、うまく機能しています。
次のコードに欠けているものはありますか、それとも Linux 側で変更する必要があるものはありますか? JPanelでsetDoubleBuffered(true)を試してみましたが、ちらつきは解消されませんでした。
以下のデモでコードの変更を参照してください。
import static java.awt.GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagLayout;
import java.awt.Paint;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class GradientTranslucentWindowDemo extends JFrame implements ActionListener {
private Timer timer = new Timer(100, this);
private double percentage = 0.0;
private JPanel surface = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (g instanceof Graphics2D) {
final int R = 0;
final int G = 240;
final int B = 240;
Paint p =
new GradientPaint(0.0f, 0.0f, new Color(R, G, B, 0),
0.0f, getHeight(), new Color(R, G, B, 255), false);
Graphics2D g2d = (Graphics2D)g;
// CHANGE 1
// Clear the previous graphics using a completely transparent fill
g2d.setBackground(new Color(0, 0, 0, 0));
g2d.clearRect(0, 0, getWidth(), getHeight());
g2d.setPaint(p);
// CHANGE 2
// Only do a gradient fill for the current percentage of the width
g2d.fillRect(0, 0, (int)Math.ceil(getWidth() * percentage), getHeight());
}
}
};
public GradientTranslucentWindowDemo() {
super("GradientTranslucentWindow");
setBackground(new Color(0,0,0,0));
setSize(new Dimension(300,200));
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// CHANGE 3
// I thought this might remove the flicker, nope
this.surface.setDoubleBuffered(true);
// CHANGE 4
// This seems to be required or the g2d.clearRect doesn't do anything
this.surface.setOpaque(false);
setContentPane(this.surface);
setLayout(new GridBagLayout());
add(new JButton("I am a Button"));
}
// CHANGE 5
// On each tick of the timer increment the percentage until its
// more than one and always repaint
@Override
public void actionPerformed(ActionEvent event) {
this.percentage += 0.05;
if (this.percentage > 1.0) {
this.percentage = 0.0;
}
this.surface.repaint();
}
public static void main(String[] args) {
// Determine what the GraphicsDevice can support.
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
boolean isPerPixelTranslucencySupported =
gd.isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT);
//If translucent windows aren't supported, exit.
if (!isPerPixelTranslucencySupported) {
System.out.println(
"Per-pixel translucency is not supported");
System.exit(0);
}
JFrame.setDefaultLookAndFeelDecorated(true);
// Create the GUI on the event-dispatching thread
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
GradientTranslucentWindowDemo gtw = new GradientTranslucentWindowDemo();
// Display the window.
gtw.setVisible(true);
// CHANGE 6
// Wait until the window is visible to start the timer
gtw.timer.start();
}
});
}
}
更新 1: 半透明を削除し、黒い背景を選択すると、ちらつきの問題が修正されます。ちらつきは、半透明のウィンドウを持つことに最も確実に関連しています。また、ウィンドウを拡大するとちらつきがひどくなることに気付きました。
更新 2:
行this.surface.setOpaque(false);
が問題の原因です。これをコメントアウトすると、アニメーションがちらつかず、半透明になります。 ただし、アニメーションを反復するたびに、前のペイントとブレンドされます(再ペイントする前に内容がクリアされません)。が設定されていない限り何もしませg2d.setBackground(new Color(0, 0, 0, 0));
ん。この行は、Linux でダブル バッファリングを無効にしているようです。g2d.clearRect(0, 0, getWidth(), getHeight());
this.surface.setOpaque(false);
半透明の窓が必要です。