Was ist eine Glass Pane?
Ein Top
Level Container wie JWindow
, JFrame
oder
JDialog
besteht aus mehreren Schichten, die jeweils eingene Aufgaben
besitzen und gesondert angesprochen werden können. Am
bekanntesten dürfte die Content Pane sein, die zur
Aufnahme der auf dem Container sichtbaren Komponenten dient.
Das
Beispiel zeigt, wie ein Glass Pane gesetzt wird und wie es
verwendet werden kann.
Auf einem von JFrame
abgeleiteten Fenster wird ein
Bild dargestellt, das in der Mitte von einem JButton
überlagert wird. Eine zur Hälfte voll und zur Hälfte
halb transparente Glass Pane überlagert das Ganze. Sie ist bei
einem MouseListener
angemeldet, der die Mausposition
registriert und der MouseEvents über der Hälfte des
Buttons an diesen weitergeleitet.
In init()
wird ein JPanel
erzeugt, das
opaque gesetzt und mit einer Hintergrundfarbe versehen wird. Ein JLabel
wird dem JPanel
hinzugefügt. Nach dem Laden einer
Bilddatei wird diese in ein ImageIcon
konvertiert und
dieses dann auf das JLabel
gesetzt, das
anschließend an die Größe des ImageIcons angepasst
wird.
Ein neu gebildetes JButton
-Objekt wird dem JPanel
hinzugefügt, und die Größe des Fensters so
eingestellt, dass sie etwas größer als das Label ist, um
einen grauen Rand zu zeigen.
Da dem JPanel
kein LayoutManager zugewiesen wurde,
muss die Methode paint()
des Fensters
überschrieben werden, um das Label und den Button zu
zentrieren. Hierzu wird deren Position über die Maße des
Labels und Panels berechnet und mittels setBounds()
schließlich absolut gesetzt.
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
public class GlassPaneDemo extends JFrame {
private JPanel panel;
private JLabel label;
private JButton butt;
private BufferedImage img;
private String imgName = "test.jpg";
public GlassPaneDemo() {
init();
}
public void init() {
label = new JLabel();
panel = new JPanel();
panel.setOpaque(true);
panel.setBackground(Color.DARK_GRAY);
panel.add(label);
loadImage();
ImageIcon icon = new ImageIcon(img);
label.setIcon(icon);
label.setSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
butt = new JButton("Klick");
panel.add(butt, 0);
setSize(label.getWidth() + 40, label.getHeight() + 60);
Glass glass = new Glass(butt, label, this);
butt.addMouseListener(new ButtonMouseListener(glass, getContentPane(), butt) {
public void mouseReleased(MouseEvent e) {
System.out.println("Button angeklickt");
}
});
getContentPane().add(panel);
setGlassPane(glass);
glass.setVisible(true);
setTitle("GlassPane Demo");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
this.setVisible(true);
}
public void paint(Graphics g) {
int x = (panel.getWidth() - label.getSize().width) / 2;
int y = (panel.getHeight() - label.getSize().height) / 2;
label.setBounds(x, y, img.getWidth(), img.getHeight());
butt.setBounds(panel.getWidth() / 2 - butt.getWidth() / 2, 200,
butt.getWidth(), butt.getHeight());
super.paint(g);
}
public void loadImage() {
File source = new File(imgName);
if (source.canRead() && source.isFile()) {
try {
img = ImageIO.read(source);
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (img == null) {
System.err.println("Kein Bild geladen.");
System.exit(1);
}
}
public static void main(String[] args) {
new GlassPaneDemo();
}
}
Um eine Glass Pane zu setzen wird eine Klasse Glass
von JComponent
abgeleitet. In der Klasse wird deren
Methode paintComponent()
überschrieben, um ein
teiltransparentes Rechteck zeichnen zu können. Dessen
Größe wird aus der Größe des Labels berechnet,
das zu diesem Zweck an den Konstruktor der Klasse Glass
übergeben wird.
Dem Glass Pane wird im Konstruktor noch ein
MouseListener
hinzugefügt. Er soll die
Möglichkeit demonstrieren, ein Mausereignis an den darunter
liegenden JButton
weiterzureichen.
class Glass extends JComponent {
JLabel label;
public Glass(JButton butt, JLabel label, RootPaneContainer parent) {
this.label = label;
this.addMouseListener(new ButtonMouseListener(this,
parent.getContentPane(), butt));
}
public void paintComponent(Graphics g) {
Rectangle rect = label.getBounds();
int x = rect.x + rect.width / 2;
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(new Color(0.5f, 0.5f, 0.5f, 0.8f));
g2d.fillRect(x, rect.y, rect.width / 2, rect.height);
}
}
Der MouseListener
ist zu Demonstrationszwecken von MouseAdapter
abgeleitet und überschreibt lediglich mouseReleased()
.
In der Methode werden die Koordinaten der Maus ausgegeben und eine
Methode redispatchMouseEvent()
aufgerufen, in der das
MouseEvent
an den unter dem Glass Pane gelagerten JButton
weitergereicht wird. Die Methode entstammt in veränderter Form
Oracles Java Tutorial How to use Root Panes.
In ihr wird
zunächst der aktuelle Punkt der Maus ermittelt. Durch die
statische Methode convertPoint()
der Klasse SwingUtilities
wird der Punkt auf die Content Pane des Fensters transpositioniert.
Die Methode getDeepestComponentAt()
ermittelt dann die
dort liegende Komponente, den Button.
Befindet sich der
ermittelte Punkt über dem Button und auf der rechten
Hälfte der Glass Pane, so wird die Punktlage von dieser auf
den Button übertragen, der daraufhin das an ihm registrierte
Ereignis verschickt.
class ButtonMouseListener extends MouseAdapter {
Component glass;
Container contentPane;
JButton butt;
public ButtonMouseListener(Component glass, Container contentPane, JButton butt) {
this.glass = glass;
this.contentPane = contentPane;
this.butt = butt;
}
public void mouseReleased(MouseEvent e) {
redispatchMouseEvent(e);
System.out.println("mouse released at " + e.getX() + "/" + e.getY());
}
private void redispatchMouseEvent(MouseEvent e) {
Point gpPoint = e.getPoint();
Point cpPoint = SwingUtilities.convertPoint(glass,
gpPoint, contentPane);
Component button = SwingUtilities.getDeepestComponentAt(contentPane,
cpPoint.x, cpPoint.y);
if ((button != null) && (button.equals(butt))
&& gpPoint.x >= glass.getWidth() / 2) {
Point buttPoint = SwingUtilities.convertPoint(glass,
gpPoint, button);
button.dispatchEvent(new MouseEvent(button, e.getID(), e
.getWhen(), e.getModifiers(), buttPoint.x,
buttPoint.y, e.getClickCount(), e.isPopupTrigger()));
}
}
}