Wie kann man ein transparentes Fenster erzeugen? v.1.7

Ein transparentes Fenster kann wahlweise mit transparenten oder mit opaken Kindelementen erzeugt werden, vorausgesetzt die zugrunde liegende Plattform ermöglicht dies.

Ab Java 1.7 steht die inoffizielle Klasse com.sun.awt.AWTUtilities nicht mehr zur Verfügung. Das Erzeugen eines transparenten JFrame, das durch die Methode AWTUtilities.setWindowOpaque(boolean) ermöglicht wurde, kann aber auf andere Weise erreicht werden. Man unterscheidet zwei Varianten. Bei der ersten wird das vollständige Fenster einschließlich der Kindelemente einheitlich transparent, bei der zweiten können Kindelemente in einem transparenten Fenster opak dargestellt werden.

Vorher sollte jedoch geprüft werden, ob die zugrunde liegende Plattform Transparenz unterstützt.

Voraussetzungen prüfen

Nach den beiden o.a. Möglichkeiten handelt es sich um zwei verschiedene Implementierungen, die auch gesondert geprüft werden müssen. Die Methode isWindowTranslucencySupported() der Klasse GraphicsDevice erwartet als Parameter eine Enum-Konstante vom Typ GraphicsDevice.WindowTranslucency und gibt einen boolschen Wert zurück. Die Konstante bestimmt hierbei, auf welchen Transparenztyp geprüft werden soll.

Das benötigte GraphicsDevice-Objekt wird über das GraphicsEnvironment ermittelt:

GraphicsEnvironment ge =
    GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();

In den beiden folgenden Beispielen wird die jeweilige Abfrage der Systemvoraussetzungen in der Methode boolean supportsTranslucency() gekapselt.

Einheitliche Transparenz

Das folgende Beispiel zeigt ein transparentes Fenster mit einem ebenfalls transparenten JButton. Um es auch bei hoher Transparenz testen zu können, wird es nicht durch den Button, sondern durch <Cmd>-Klick geschlossen und ist trotz der fehlenden Fensterleiste verschiebbar. Achtung! Wird das Fenster vollständig transparent dargestellt (setOpacity(0)), erlaubt das Fenster keine Ereignisbehandlung mehr!

public class TranspFenster extends JFrame {

    Point point = new Point();

    public TranspFenster() {
        init();
    }

    private void init() {
        this.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                if (!e.isMetaDown()) {
                    point.x = e.getX();
                    point.y = e.getY();
                } else {
                    System.exit(0);
                }
            }
        });
        addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseDragged(MouseEvent e) {
                if (!e.isMetaDown()) {
                    Point p = getLocation();
                    setLocation(p.x + e.getX() - point.x,
                            p.y + e.getY() - point.y);
                }
            }
        });
        this.add(new JButton("klick"), BorderLayout.SOUTH);
        this.setLocationRelativeTo(null);
        this.setSize(400, 300);
        if (supportsTranslucency()) {
            this.setUndecorated(true);
            this.setOpacity(0.35f);
        }
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
    
    private boolean supportsTranslucency() {
        GraphicsEnvironment ge = GraphicsEnvironment
                .getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        return gd.isWindowTranslucencySupported(
                GraphicsDevice.WindowTranslucency.TRANSLUCENT);
    }

    public static void main(String[] args) {
        new TranspFenster();
    }
}

Das Fenster selbst ist ein gängiger, verschiebbarer JFrame, dessen Aufbau hier nicht näher besprochen wird. Enscheidend im vorliegenden Zusammenhang sind die beiden Zeilen

this.setUndecorated(true);
this.setOpacity(.35f);

Die Transparenz wird durch die Methode setOpacity() erzeugt. Sie erwartet einen float-Parameter mit Werten zwischen 0 (vollständige Transparenz) und 1 (vollständige Opazität). Bei Werten kleiner als 1 muss die Fensterleiste des Frame mit setUndecorated(true) zwingend entfernt werden, um eine IllegalComponentStateException zu vermeiden.

einheitlich transparentes Fenster

Teiltransparenz

Um die Kindelemente eines JFrame opak und den Frame selbst tansparent zu zeichnen, muss ein kleiner Umweg über einen JPanel gegangen werden.
Das Beispiel zeigt einen transparenten JFrame mit opakem Rand und JButton, über den das Fenster geschlossen werden kann.

public class TranspFenster extends JFrame {

    public TranspFenster() {
        init();
    }

    private void init() {
        JPanel panel = new JPanel() {
            @Override
            public void paintComponent(Graphics g) {
            }
        };
        this.add(panel);
        JButton butt = new JButton("exit");
        butt.addActionListener(e -> System.exit(0));
        panel.add(butt);
        panel.setBorder(new LineBorder(Color.BLACK));
        
        if (supportsTranslucency()) {
            this.setUndecorated(true);
            setBackground(new Color(0, 0, 0, 25));
        }
        
        this.setLocationRelativeTo(null);
        this.setSize(400, 300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
    
    private boolean supportsTranslucency() {
        GraphicsEnvironment ge = GraphicsEnvironment
                .getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        return gd.isWindowTranslucencySupported(
                GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT);
    }

    public static void main(String[] args) {
        new TranspFenster();
    }
}

Im Beispiel wird in init() ein JPanel erzeugt, dem ein Button und ein Rand hinzugefügt werden. Um die gewünschte Transparenz zu erlangen muss paintComponent() des Panels überschrieben werden. Es darf jedoch nicht super.paintComponent() aufgerufen werden. Darüber hinaus kann die Methode wahlweise leer bleiben oder z.B., wie von Oracle gezeigt, mit einem Farbgradienten versehen werden.
Die Transparenz des JFrame wird durch entsprechendes Setzen des Hintergrundes erreicht. Hierzu wird ein Color-Objekt verwendet, das als vierten Parameter, nach den Werten für rot, gelb und blau, ebenfalls einen Wert zwischen 0 (vollständige Transparenz) und 255 (vollständige Opazität) erhält. Zudem muss auch hier die Fensterleiste entfernt werden.

this.setUndecorated(true);
setBackground(new Color(0, 0, 0, 25));

Das Setzen der Hintergrundfarbe entspricht somit derjenigen Funktionalität, die unter Java 6.10 AWTUtilities.setWindowOpaque(boolean) übernommen hatte.

teiltransparentes Fenster

Quellen

https://docs.oracle.com/javase/tutorial/uiswing/misc/trans_shaped_windows.html