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 TransparentesFenster2 {

    Point point = new Point();

    public TransparentesFenster2() {
        init();
    }

    private void init() {
        JFrame frame = new JFrame();
        // Verschiebbarkeit und Schlie├čen des Fensters
        frame.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                if (!e.isMetaDown()) {
                    point.x = e.getX();
                    point.y = e.getY();
                } else {
                    System.exit(0);
                }
            }
        });
        // Verschiebbarkeit des Fensters
        frame.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseDragged(MouseEvent e) {
                if (!e.isMetaDown()) {
                    Point p = frame.getLocation();
                    frame.setLocation(p.x + e.getX() - point.x, p.y + e.getY() - point.y);
                }
            }
        });
        JButton butt = new JButton("klick");
        butt.addActionListener(e -> System.exit(0));
        frame.add(butt, BorderLayout.SOUTH);
        frame.setLocationRelativeTo(null);
        frame.setSize(400, 300);
        if (supportsTranslucency()) {
            frame.setUndecorated(true);
            frame.setOpacity(0.35f);
        }
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.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) {
        SwingUtilities.invokeLater(() -> new TransparentesFenster2());
    }
}

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

frame.setUndecorated(true);
frame.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 TransparentesFenster3 {

    public TransparentesFenster3() {
        init();
    }

    private void init() {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel() {
            // muss ├╝berschrieben werden, um Transparenz zu erreichen
            @Override
            public void paintComponent(Graphics g) {
            }
        };
        frame.add(panel);
        JButton butt = new JButton("exit");
        butt.addActionListener(e -> System.exit(0));
        panel.add(butt);
        panel.setBorder(new LineBorder(Color.BLACK));

        if (supportsTranslucency()) {
            frame.setUndecorated(true);
            frame.setBackground(new Color(0, 0, 0, 25));
        }

        frame.setLocationRelativeTo(null);
        frame.setSize(400, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.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) {
        SwingUtilities.invokeLater(() -> new TransparentesFenster3());
    }
}

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