Wie kann man ein transparentes Fenster erzeugen? v.1.7
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.
TRANSLUCENT
lieferttrue
, wenn eine einheitliche Transparenz unterstützt wird.PERPIXEL_TRANSLUCENT
lieferttrue
, wenn ein Fenster Pixel mit unterschiedlicher Transparenz enthalten kann.
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.
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.
Quellen
https://docs.oracle.com/javase/tutorial/uiswing/misc/trans_shaped_windows.html
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.