EventHandling

fsicher

Bekanntes Mitglied
Folgende Situation:

In einem JPanel-Conatainer (Level 1) werden weitereJPanel-Container (Level 2) verwaltet, die wiederum weitere JPanel-Komponenten (Level 3) enthalten. Der Inhalt eines Level 3 JPanels wird geändert, das ganze muss neu gezeichnet werden, wobei die Zeichnung von dem Level 1 JPanel durchgeführt werden muss (komplexe Berechnung des Layouts ...). Wie macht man das am besten?

Ich könnte die Level 1 JPanel bei dem Level 3 JPanel als ComponentListener registrieren und dann ein ComponentEvent werfen (COMPONENT_RESIZED) und die entsprechende Methode des ComponentListeners passend implementieren. Das setzt voraus, dass ich die Referenz auf en Level 1 JPanel über zwei Ebene weitergeben muss, was mir nicht so gefällt. Insbesondere deshalb, weil die JPanel-Komponenten als Views dienen, während die Daten in einer Model-Klasse verwaltet werden. Die Views sollten möglichst lokal gehalten werden. Gibt es nicht eine einfachere Variante, dies zu bewerkstelligen? Kann ich es irgendwie anders sicherstellen, dass ein vom Level 3 JPanel gefeuertes Event vom Level 1 JPanel doch empfangen wird? Gibte es irgendwo eine "allgemein bekannte" Event-Queue, in die ich das Ereignis einfügen könnte (EDT usw.)?

Es geht nicht darum, dass ich einfach repaintComponent oder so was aufrufe. Ich muss eine Methode des Level 1 JPanels aufrufen, die eine relativ komplexe Berechnung (Layout ... ) macht. Dazu muss ich irgendwie die Meldung an den Level 1 JPanel senden. Kann man das eleganter machen, als die Referenz über drei Ebene weiterzureichen?

Danke
 

ymene

Bekanntes Mitglied
Ich denke der EventBus wäre hierfür gut geeignet. In deinem Fall würde das Level 3 JPanel ein Event senden, dass sich seine Größe verändert hat und jeder der sich dafür interessiert (sprich das Level 1 JPanel) kann sich einfach für dieses Event registrieren und entsprechend darauf reagieren. So kann man verhindern, dass untereinander Referenzen benötigt werden und verhindert somit eine enge Kopplung.
 

fsicher

Bekanntes Mitglied
Danke für die Antwort. Ich habe mir EventBus kurz angeschaut: das wäre eine Alternative. Ich muss aber versuchen, es ohne zusätzliche Bibliotheken zu realisieren.

Wenn ein Container neu gezeichnet wird, werden alle enthaltene Komponenten (child-Komponenten) gezeichnet, indem deren Methoden paint / repaint aufgerufen werden: Level 1 JPanel --> ... --> Level 3 JPanel. Kann dies auch in andere Richtung bewerkstelligt werden? Kann ich aus Level 1 JPanel durch aufruf von validate / revalidate oder was auch immer den Parent-Container zwingen, dass er alle seine Komponenten neu zeichnet? Natürlich, ohne das ich Referenz auf das Parent-Container extra verwalten muss. Oder, geht das wirklich nur über Events, die gefeuert werden?

Danke.
 
G

Gast2

Gast
He? Mach mal ein KSKB kein Plan was du vor hast ^^...
Alle Views im Model registrieren genügt nicht?
 

fsicher

Bekanntes Mitglied
Gut, ich versuh's!

Java:
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class JPanelL1 extends JPanel {

	int value = 0;

	static JPanelL3 pA = null;

	public JPanelL1() {
		setLayout(new GridLayout(1, 3, 5, 5));
		init();
	}

	private void init() {
		JPanelL2 jpL2A, jpL2B, jpL2C;

		jpL2A = new JPanelL2();
		jpL2B = new JPanelL2();
		jpL2C = new JPanelL2();

		add(jpL2A);
		add(jpL2B);
		add(jpL2C);

		pA = new JPanelL3();

		jpL2C.add(pA);

		setVisible(true);
	}

	/* (non-Javadoc)
	 * @see java.awt.Component#repaint()
	 */
	public void repaint() {
		super.repaint();
		System.out.println("Wert: " + ++value);
	}
	
	public static void main(String[] args) {
		JPanelL1 p = new JPanelL1();

		JFrame frm = new JFrame("Test-Frame");
		frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frm.add(p);
		frm.pack();
		frm.setVisible(true);
	}

	
}

class JPanelL2 extends JPanel {
	public JPanelL2() {
		setLayout(new GridLayout(1, 2, 5, 5));
		setBackground(Color.yellow);
		setBorder(BorderFactory.createEmptyBorder());
	}
}

class JPanelL3 extends JPanel implements ActionListener {
	JPanelL3() {
		setLayout(new FlowLayout());
		setBackground(Color.LIGHT_GRAY);
		setBorder(BorderFactory.createEtchedBorder());

		JButton btnAdd = new JButton("Add JLabel");
		btnAdd.addActionListener(this);

		add(btnAdd);
	}


	@Override
	public void actionPerformed(ActionEvent e) {
		repaint();
	}
}

Wenn ich auf btnAdd im Level 3 JPanel (pA) klicke, soll die Methode repaint des Level 1 JPanels aufgerufen werden: value wird inkrementiert und ausgegeben. Das funktioniert aber nicht. Wenn ich aber die Fenstergrösse ändere, funktioniert es. Ich nehme an, dass dabei ein Event im Spiel ist (WindowResize oder so was ähnliches). Also: Wie kann ich aus der Child-Komponente das Neuzeichnen des Parent-Containiers veranlassen, ohne dass ich dabei den Parent-Container bei der Child-Komponente explizit als XXXListener anmelden muss?
 

Michael...

Top Contributor
Hab jetzt nicht verstanden warum das Neuzeichnen einer Komponente das Neuzeichnen des ganzen Containers anstossen soll/muss.

Aber wenn es, um so übergreifende Aktionen geht. Wie wäre es mit einen zentralen Controller der per Event von Level3 informiert wird und anhand des Events erkennt was zu tun ist, z.B. ab Level1 alles neu zeichnen.
 

Ähnliche Java Themen


Oben