Java Standard: Grafische Oberflächen mit Swing: leightweight Container: javax swing JPanel


Das JPanel ist die analoge Komponente zum java.awt.Panel und deckt auch die Funktionalitäten von java.awt.Canvas ab.

Die leichtgewichtige Containerklasse JPanel dient hauptsächlich der Aufnahme bzw. Klammerung von Swing-Komponenten. Möchte man beispielsweise in einem Top-Level-Container mit BoxLayout zwei unterschiedliche Komponenten im Bereich PAGE_END unterbringen, so muss man diese zunächst in einem JPanel zusammenfassen und kann dieses dann dem PAGE_END-Bereich mitsamt den enthaltenen Komponenten hinzufügen.

Die Erzeugung von Objekten der Klasse JPanel geschieht wie üblich über den Konstruktor.

	...
	// Erzeugt JPanel mit FlowLayoutManger
	JPanel panel1 = new JPanel();
	...

LayoutManager festlegen

Bearbeiten

Der LayoutManager eines JPanel Objekts bestimmt die Anordnung und teilweise das Verhalten der enthaltenen Komponenten. Standardmäßig erhält ein JPanel-Objekt bei Erzeugung durch new JPanel() einen FlowLayoutManager. Um einem JPanel bei Erzeugung einen anderen LayoutManager zuzuweisen, wird dieser einem anderen Konstruktor übergeben.

	...
	// Erzeugt JPanel mit BorderLayout
	JPanel panel1 = new JPanel( new BorderLayout() );
	...

Notiz: Eine Ausnahme hierbei bildet BoxLayout, da es nur einem bereits bestehenden Container zugewiesen werden kann. Dies kann mittels der folgenden Methode geschehen.

	...
	// Erzeugt JPanel mit FlowLayout
	JPanel panel1 = new JPanel(  );

	// weist diesem JPanel ein BoxLayout, mit vertikaler
	// Orientierung der enthaltenen Komponenten hinzu
	panel1.setLayout( new BoxLayout( panel1, BoxLayout.PAGE_AXIS ) );
	...

Der Konstruktor der Klasse BoxLayout erwartet dabei die Übergabe des Containers und einer Konstante zum setzen der Orientierung der enthaltenen Komponenten.

Komponenten hinzufügen - Jetzt wird`s voll

Bearbeiten

Komponenten können mittels der add()-Methoden hinzugefügt werden. Ein JPanel kann Objekte vom Datentypen Component aufnehmen, folglich alle Erben dieser Klasse und somit ebenfalls JPanel-Objekte.

 

	...
	// Erzeugt einen JButton mit dem Text OK
	JButton button1 = new JButton("OK");

	// Fügt den JButton zum JPanel hinzu
	panel1.add( button1 );

        // fügt das JPanel einem JFrame im PAGE_END-Bereich 
        // des BorderLayouts hinzu
	einFrame.add( panel1, BorderLayout.PAGE_END );
	...

Das Standard-Layout ist FlowLayout und das JPanel wird im PAGE_END-Bereich des BorderLayouts des JFrames hinzugefügt. Dadurch wird die Höhe des JPanels durch die enthaltenen Komponenten bestimmt. Setzt man hingegen mittels der Methode setPreferredSize( Dimension ) die Höhe auf einen bevorzugten Wert, wird hierdurch die Höhe bestimmt.

Hält das JPanel ein BorderLayout muss noch spezifiziert werden, in welchem Bereich des BorderLayouts die Komponente abgelegt werden soll. Durch das BorderLayout wird der Button jedoch auf die gesamte Breite des JPanels gestreckt.

 

	...
        // JPanel mit BorderLayout
        JPanel panel1 = new JPanel( new BorderLayout() );

	// Erzeugt einen JButton mit dem Text OK
	JButton button1 = new JButton("OK");

	// Fügt den JButton zum JPanel hinzu
	panel1.add( button1, BorderLayout.PAGE_END );

        // fügt das JPanel einem JFrame im PAGE_END-Bereich 
        // des BorderLayouts hinzu
	einFrame.add( panel1, BorderLayout.PAGE_END );
	...

Ein JPanel hält die hinzugefügten Komponenten in einer Datenstruktur (eine Liste), die einen Index führt. Somit können Komponenten an bestimmten Stellen dieser Liste abgelegt werden. Der Index beginnt bei 0.

	...
	// Erzeugt einen JButton mit dem Text OK
	JButton button1 = new JButton("OK");

	// Fügt den JButton an der vierten Position der intern verwendeten
	// Datenstruktur des JPanels ein
	panel1.add( button1, 3 );
	...

Komponenten holen - getComponent()

Bearbeiten

Um Komponenten aus einem JPanel zurückgeben zu lassen, muss man entweder wissen an welcher Index- oder x,y-Position sie sich befindet.

Notiz: Die Methode getComponent() gibt ein Objekt vom Datentypen java.awt.Component zurück. Daher kann auf ein so geholtes Objekt die getComponent() Methode nicht mehr angewandt werden. Diese ist Teil der Klasse java.awt.Container. Um den vollen Funktionsumfang eines auf diese Weise geholten Objektes zugreifen zu können, muss ein Typecast durchgeführt werden. In folgendem Beispiel wird nach (JButton) gecastet.

        ...
	// Erzeugt einen JButton mit dem Text OK
	JButton button1 = new JButton("OK");

	// Fügt den JButton zum JPanel hinzu
	panel1.add( button1 );

	// gibt Component an der nullten Position zurück
	JButton button2 = (JButton) panel1.getComponent( 0 );

	// gibt Component an der definierten x,y Position innerhalb 
	// des Containers zurück
	JButton button3 = (JButton) panel1.getComponent( 20, 40 );ö
	...

Möchte man also den kompletten "Pfad" vom Top-Level Container bis zu einem JPanel durchlaufen, muss dies in mehreren Schritten geschehen.

        ...   
        JFrame f = new JFrame("Test Frame");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel p = new JPanel( new BorderLayout() );
	JButton b = new JButton("OK");

	p.add(b, BorderLayout.PAGE_END);

        f.add( p, BorderLayout.PAGE_END );

        f.setSize( 300, 200 );
        f.setVisible(true);

        // Holt das JPanel als Component aus dem ContentPane des JFrames und 
        // führt einen Typecast nach Container durch, damit eine Zeile später auf 
        // die Methode getComponent() zugegriffen werden kann
	Container tempContainer = (Container) f.getContentPane().getComponent(0);
        
        // Den JButton als Component aus dem temporären Container 
        // holen und Class ausgeben lassen
	System.out.println( tempContainer.getComponent(0).getClass() );
        ...

Komponenten entfernen - raus damit

Bearbeiten

Wenn man etwas hinzufügen kann, kann man es auch wieder entfernen. Dies geschieht bei JPanel mittels der Methode remove(). Möchte man auf JPanel zugreifen um daraus Komponenten zu entfernen, kann dies mittels der oben beschriebenen Methode getComponent() geschehen.

	...
	// entfernt die Komponente am Index = 5
	panel1.remove( 5 );

	// entfernt das übergebene Component Objekt
	panel1.remove( button1 );

	// entfernt alle Komponenten des JPanels
	panel1.removeAll();
	...

Farben verändern - Jetzt wird's bunt

Bearbeiten

JPanel sind standardmäßig durchsichtig, was, begründet durch ihre Hauptaufgabe auch sinnvoll ist. Um ein JPanel undurchsichtig zu machen, muss man folgende Methode aufrufen.

	...
	// setzt ein JPanel undurchsichtig
	panel1.setOpaque( true );
	...

Nachdem ein JPanel undurchsichtig gesetzt ist, kann die Hintergrundfarbe durch übergeben eines Color Objektes gesetzt werden. Das JPanel wird allerdings auch ohne den Aufruf der Methode setOpaque( true ), also durch alleinigen Aufruf der Methode setBackground( java.awt.Color ) undurchsichtig.

 

	...
        JFrame f = new JFrame("Test Frame");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel p = new JPanel( new BorderLayout() );

        p.setOpaque( true );
        p.setBackground( new Color( 0,0,230 ) );
	p.setPreferredSize( new java.awt.Dimension( 10, 50 ) );

        f.add( p, BorderLayout.PAGE_END );
	...

Border - Grenzen ziehen

Bearbeiten

Man kann einem JPanel unterschiedlichste Borders zuweisen. Hier das Beispiel einer einfachen schwarzen Linie als Grenze. Dazu wird auf eine statische Methode der Klasse BorderFactory zurückgegriffen.

 

	...
        JFrame f = new JFrame("Test Frame");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	f.setLayout( new FlowLayout() );

        JPanel p = new JPanel();
	JButton b = new JButton("OK");
	p.add( b );

	p.setPreferredSize( new java.awt.Dimension( 100, 39 ) );

        // Legt eine schwarze einfache Linie als Border um das JPanel
	p.setBorder( BorderFactory.createLineBorder( Color.black ) );

        f.add( p );

        f.setSize( 300, 200 );
        f.setVisible(true);
	...

Genaueres zu Borders und den möglichen Ausprägungen findet sich im entsprechenden Kapitel.

JPanel als Abstandhalter - Die Füllung macht`s

Bearbeiten

Auch wenn es möglich ist JPanels als Füllmaterial zu nutzen, macht es wenig Sinn und soll hier nur der Vollständigkeit halber erwähnt werden. Für die Definition von Abständen innerhalb von Containern sind die LayoutManager bzw. die Klasse javax.swing.Box zuständig. Die Klasse Box bietet spezielle Methoden zur Erzeugung von Füll-Containern.

Beispiel für Organisation von Komponenten

Bearbeiten

Folgende Abbildung soll die Organisation von Komponenten mittels JPanels darstellen.

 

Als Top-Level Container dient javax.swing.JDialog mit einem java.awt.BorderLayout. Das JPanel mit Fortschrittsanzeige ist im LINE_START-Bereich und das JPanel mit Buttons zur Navigation im PAGE_END-Bereich angesiedelt. Im CENTER-Bereich des JDialogs sitzt ein JPanel mit BorderLayout, das wiederum zwei JPanel mit einem Scrollpane sowie einer Gruppe Radiobuttons enthält.