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 JFrame
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 weiterleitet.
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 {
private static final long serialVersionUID = 1L;
private JFrame frame;
private JPanel panel;
private JLabel label;
private JButton butt;
private BufferedImage img;
private String imgName = "src/img/wien.jpg";
public GlassPaneDemo() {
init();
}
public void init() {
frame = new JFrame("GlassPane-Demo") {
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());
}
};
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);
frame.setSize(label.getWidth() + 40, label.getHeight() + 60);
Glass glass = new Glass(butt, label, frame);
butt.addMouseListener(new ButtonMouseListener(glass, frame.getContentPane(),
butt) {
public void mouseReleased(MouseEvent e) {
System.out.println("Button angeklickt");
}
});
frame.getContentPane().add(panel);
frame.setGlassPane(glass);
glass.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
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) {
SwingUtilities.invokeLater(() -> 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()));
}
}
}
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.