Strategie für tief ineinander geschachtelte GUI Komponenten

Uwe_

Grünschnabel
Hallo,

ich bin leider noch ein Programmieranfänger, aber habe es derzeit mit einem größeren Projekt zu tun.
Kleinere Schwierigkeiten lassen sich gut durch nachlesen lösen, aber nun habe ich ein generelles Problem.

Wenn ich die GUI Komponenten entwerfe, versuche ich mir die Arbeit zu erleichtern, indem ich alles in mehrere JPanels aufspalte. Dann lege ich z.B. ein Frame an und lege all diese Panels drauf. Manchmal enthält ein Panel wiederum ein Panel, wenn zu viele kleine Komponenten beteiligt sind.
Das Problem ist nun, angenommen es gibt einen Button in einem der Panels ganz tief in der Hierarchie. Dieser soll aber eine Aktion auslösen, die eine ganz andere Komponente im System berifft. Wie delegiert man am besten so eine Aktion wieder nach ganz oben? Sollte ich lieber schachteln generell vermeiden?
Ich habe mich bereits etwas in das MVC Muster eingelesen, muss aber gestehen, dass ich es noch nicht ganz verstanden habe. Wenn man all diese Panels als View interpretiert, muss man jedem der Panels den zugehörigen Controller und das zugehörige Model übergeben?
Ich will möglichst keinen big Blob am Ende programmieren :) Aber mir fehlt die Erfahrung, wie man sowas angehen kann.
 

Anhänge

  • temp2.gif
    temp2.gif
    3,3 KB · Aufrufe: 3
Ich habs nun erstmal so gelöst, dass ich jedem Unterelement das Oberelement im Konstruktor übergebe, quasi eine Referenz auf das parent-Element.

Wahrscheinlich ist das der einfache naive Weg. Man muss dann irgendwie die Methoden doppelt führen und bei Änderungen synchronisieren. Also wenn ich in der Unterkomponente (z.B. ein Panel) bei Klick auf einen Button aufrufe:

innereKlasse ActionListener...{
machWas();
}

private void machWas(){
parent.machWas();}


dann muss entsprechende Methode in der Oberkomponente (z.B. ein Frame) synchron gehalten werden. Wenn ich dann in der Methode im Frame was ändere und nicht mehr weiß, dass tief verschachtelt in der Hierarchie da eine Methode sitzt, dann hab ich ein Problem.

Ich vermute aber mal das ist ein typisches Anfängerproblem, ist halt ein frustrierender Weg bis zum Experten. Wenn man wenig Erfahrung hat, ändern sich halt die Schnittstellen oft, weil man es noch nicht besser kann :/
 
Das Problem hättest du gar nicht erst, wenn du nicht verschachteln, sondern einen LayoutManager wie den GridBagLayout-Manager verwenden würdest. Ich weiß, dass viele den nicht mögen, wegen angeblicher Einarbeitungsschwierigkeiten und anderem, aber eigentlich ist es echt simpel damit umzugehn und man braucht keine verschachtelten Irrgärten zu basteln.
 
Hmm, ich glaube nicht, dass es nur an dem Layout-Manager liegt. Aber danke für den Tipp, ich glaube es lohnt sich sehr, wenn man das GridBagLayout beherrscht.

Ich hab spaßeshalber mal meine Idee mit dem Interface für ein bestimmtes Panel getestet. Dieses Panel ist im Bild zu sehen und taucht (geschätzt) 3-4 mal im Programm auf. Deshalb lohnt es sich wohl grade so da ein Muster drüberzulegen.

Dieses Panel implementiert ein Interface ControlButtonInterface:
Code:
public interface ControlButtonInterface {
	public void saveButtonAction();
	
	public void applyButtonAction();
	
	public void cancelButtonAction();
}

Das Frame, das dieses Panel enthält implementiert ebenso dieses Interface. Wenn ich nun ein ControlButtonPanel erstelle übergebe ich im Konstruktor das Parent. Hier hat man allerdings ein Problem, den schwups braucht man eine abstrakte-Fabrik, die auch dieses Interface implementiert. Sonst würde mein Ansatz nur für genau 1 Frame funktionieren.

Im ControlPanel delegiere ich die Methoden dann nach oben, also wenn eine Action auf dem Button ausgelöst wird:
masterFrame.saveButtonAction();

und im Frame steht dann die eigentliche Aktion, die dann ausgeführt wird.

Vorteil ist: Wenn man mehrere Panels im Frame hat und diese "weiterschalten" will, bekommt man schnell Probleme, wenn man versucht alles in einem riesen-Layout zu bauen.

Bei mir ist das so, ich verbinde mich zu einer DB, da werden die Connect- Informationen erstmal abgefragt. Dann verschwindet dieses Panel und wird mit einem ausgewechselt, mit dem man eine Tabelle auswählen kann. Wenn man oft genug wechselt, explodiert der Code leider :/
 

Anhänge

  • tempsteuer.gif
    tempsteuer.gif
    2,9 KB · Aufrufe: 7
Du machst das für meinen Geschmack etwas zu umständlich, wenn ich ehrlich bin. An sich ist die Idee nicht schlecht, aber du musst z.B. jedes Mal das Parent-Objekt übergeben, was nicht an jeder Stelle notwendig ist. Zudem hast du das Problem, dass wenn du in der Hierarchie in der Mitte was austauschst und die Implementierung schief geht oder du sogar vergisst was zu implementieren, dann hast du viel Spaß beim Suchen des Fehlers, auf die Schnelle wird der sich nämlich nicht finden lassen. Also das Observer-Pattern wäre wohl die bessere Wahl, weil du dann mit Events arbeitest und ganz egal, wie tief deine Struktur verschachtelt ist, die Aktion kannste dann auf deiner obersten Ebene implementieren und diese dann im entsprechenden Objekt registrieren, du musst dann nur dafür sorgen, dass man an das Objekt rankommt.

Es gibt verschiedene Möglichkeiten sowas zu lösen, man kann die Hierarchie entlangklettern und sich brav durch jede Ebene kämpfen, was wohl die sauberste Variante wäre, aber ich persönlich würde wohl einen globalen Container einrichten, in dem sich die entsprechenden Objekte Registrieren und dann darüber arbeiten, also quasi anstatt die Seitenstraßen zu benutzen lieber einmal über die Autobahn jagen, weil dann hab ich einen zentralen Anlaufpunkt und muss mich nicht durch eine eventuell gewaltige Hierarchie kloppen, was schon viel Spaß machen wird, wenn sich mitten drin was ändert, weil dann alles angepasst werden könnte, um auf die Objekte zuzugreifen.

So würde ich jedenfalls vorgehn, vielleicht fallen mir aber noch andere Wege ein.
 
Zurück