GUI Builder ActionListener

Alles was mit Swing und AWT zu tun hat

Moderatoren: wegus, Olek77

daflowjoe
Beiträge: 8
Registriert: 12.09.2012, 22:42

Re: GUI Builder ActionListener

Beitrag von daflowjoe » 21.09.2012, 11:51

Hallo nochmal,

ich habe durch die Struktur des CardLayouts allerdings jetzt das Problem dass nach dem Umschalten auf ein Card die Daten nicht nei initialisiert werden, also z.B. die Models etc. Das wird ja jeweils im Constructor der jeweiligen Panelklasse gemacht.
In meinem Fall betrifft dass vorallem ein Konfigurationsmenü. Das muesste samt Unterpanels neu initialisiert werden bevor ich zu dem Card umschalte.

Folgenden Versuch habe ich unternommen:


Klasse NavigationController (die Methode die beim Klick auf ein Navigationselement aufgerufen wird und das Card umschaltet)

Code: Alles auswählen

public void getConfigPanel(String name){
         ConfigPanel cp = (ConfigPanel)mainPanel.getParent().getParent();
        cp.removeAll();
        cp = new ConfigPanel();
        cp.validate();
        windowMainPanel.add(cp, "config");
        getCard(name);
}
Der Panel wird dann wie gefreezed. Ich kann nichts mehr anklicken, wenn ich in der Hauptnavi einmal hin und herswitche ist er danach aber leer.
Er wird aber nicht neu aufgebaut. Was ich will ist einfach, dass der gesamte Panel samt aller Unterlemente neu aufgebaut wird, so dass die Konstruktoren aufgerufen werden etc und alles refreshed wird.

Benutzeravatar
nigjo
Beiträge: 632
Registriert: 08.09.2009, 09:43
Wohnort: Aachen
Kontaktdaten:

Re: GUI Builder ActionListener

Beitrag von nigjo » 21.09.2012, 12:08

daflowjoe hat geschrieben:

Code: Alles auswählen

public void getConfigPanel(String name){
             ConfigPanel cp = (ConfigPanel)mainPanel.getParent().getParent();
            cp.removeAll();
            cp = new ConfigPanel();
            cp.validate();
            windowMainPanel.add(cp, "config");
            getCard(name);
    }
Zwei Fragen.

1. Warum heißt die Methode "get...", wenn sie nichts zurück liefert. Das verwirrt. "Getter" liefern immer etwas zurück. Wenn du die Methode zum Wechseln der Panel nutzen möchtest, solltest du sie "show..." oder so nennen.

2. Warum löschst du alle Komponenten einer UI-Instanz ("cp.removeAll"), wenn du direkt danach eine neue Instanz erzeugst, von der du irgendwelche beliebigen Methoden aufrufst. Außerdem wird die alte Instanz überhaupt nicht "abgemeldet". Wundert mich nicht, dass deine Oberfläche sich so seltsam verhält. Du wirfst da mit Klasseninstanzen nur so um Dich ohne damit irgendwas anzufangen.
daflowjoe hat geschrieben:also z.B. die Models etc. Das wird ja jeweils im Constructor der jeweiligen Panelklasse gemacht.
Mach es wo anders. Deine UI-Komponenten solltest du nach Möglichkeit exakt ein einziges Mal erzeugen. Danach werden nur noch die Daten aktualisiert, aber bitte erzeuge keine neuen Elemente.

Wie schon in einem vorherigen Post geschrieben. Die Kommunikation zwischen deinen Panel (also der Datenaustausch, der bei dir nicht funktioniert), sollte über dein Datenmodell passieren, nicht zwischen den UI-Panel direkt. Das gibt nur Chaos. Ein Beispiel für so eine Datenklasse hatte ich oben erwähnt. Schau dir das Konzept der "PropertyChangeListener" an. Damit sollte der Informationsaustausch zwischen deinen Paneln kein Problem mehr sein.

Gruß
Jens
Man sollte seine Werkzeuge kennen. Ansonsten haut man sich mit dem Hammer nur auf die Finger.

--
NetBeans Certified Engineer - Java Getriebe

daflowjoe
Beiträge: 8
Registriert: 12.09.2012, 22:42

Re: GUI Builder ActionListener

Beitrag von daflowjoe » 21.09.2012, 20:09

Was meinst du mit ueberhaupt nicht abgemeldet? Dass das designtechnisch nun beschissen ist mir klar. Ich hatte vorher nur garnicht daran gedacht, dass es da Probleme gibt und wollte eine moeglichst pragmatische Abhilfe schaffen. Dass ich da ein removeAll mach und dann die Klasse instanziere ist pure Verzweiflung, weil ich mir nicht erklaeren kann, wieso das nicht funktioniert. Was macht da java noch im Hintergrund, dass ich nicht einfach die Panelklasse neu instanzieren kann?
Dass ich die Methode zur Dateninitialisierung im Konstruktor aufrufe hat auch den Hintergrund, dass ich nicht fuer jede Panelklasse nochmal custom creation code erzeugen muss, sondern einfach meine init Methode im Konstruktor aufrufe. Ich fand das ganz praktisch und wuesste nicht was dagegen spricht?
Dass ich mich nun um jede einzelne GUI kuemmern muss, wenn sich Daten aktualisiert haben, ist mir eigentlich zuwider. Deshalb wollte ich einfach die Panels komplett neuladen und haette dies somit einfach vom Tisch.

Das von dir im Blog beschriebene Methode gefaellt mir aber ganz gut.Ich weiss nur jetzt nicht wie ich die Klasse so richtig verwenden soll.
Das Prinzip ist doch, dass ich in meineGUI Klasse als Listener anmelde und bei der Datenaenderung dann ein Event feure, so dass alle angemeldeten Klassen benachrichtigt werden, richtig? Wie aber konkret? Wie wird dann benachrichtigt? Wird eine Methode aufgerufen? Welche?
Kannst du vielleicht mal ein Beispiel geben, wie das in einer GUI Klasse dann praktisch aussieht?

Benutzeravatar
nigjo
Beiträge: 632
Registriert: 08.09.2009, 09:43
Wohnort: Aachen
Kontaktdaten:

Re: GUI Builder ActionListener

Beitrag von nigjo » 21.09.2012, 22:44

daflowjoe hat geschrieben:Das Prinzip ist doch, dass ich in meineGUI Klasse als Listener anmelde und bei der Datenaenderung dann ein Event feure, so dass alle angemeldeten Klassen benachrichtigt werden, richtig?
Korrekt. Genau das ist die Idee.
daflowjoe hat geschrieben:Wie aber konkret? Wie wird dann benachrichtigt? Wird eine Methode aufgerufen? Welche?
Kannst du vielleicht mal ein Beispiel geben, wie das in einer GUI Klasse dann praktisch aussieht?
Ich werd am WE mal versuchen ein ausführliches Beispiel zu erstellen.

Auf die Schnelle vielleicht die Stichpunktliste:
  • Es gibt eine Datenklasse, die von der Klasse aus dem Blog Eintrag abgeleitet ist.
  • Von der Datenklasse wird vor dem Erstellen der GUI EIN Objekt erstellt.
  • GUI Klassen implementieren entweder selbst oder als innere Klasse einen PropertyChangeListener
  • Die GUI Klassen erhalten eine Methode (z.B.) setData(), die von "außen" das eine Datenobjekt übergeben bekommen
  • Die GUI Elemente melden sich dort mit ihrem PCL beim Datenobjekt an.
  • Für jeden Datenwert deiner Datenklasse solltest du eine String-Konstante erstellen, die in der Datenklasse "eindeutig" ist.
  • Jede Setter Methode deiner Datenklasse rufst du die "put"-Methode der Elterklasse auf
  • In jeder getter Methode rufst du die "get" Method der Elterklasse auf
  • In den PropertyChangeListenern fragst du den evt.getPropertyName() ab und "reagierst entsprechend"
Ein schnelles Beispiel für die Datenklasse:

Code: Alles auswählen

public class DatenModel extends ObservableProperties<String>{
  public static final String NAME = "DatenModel.name";

  public void setName(String name){
    put(NAME, name);
  }

  public String getName(){
    return get(NAME);
  }
}
(ohne Gewähr, nicht getestet)

Wie gesagt, ich werd das noch Mal ausführlicher schreiben, aber vielleicht hilft das hier auch schon.

Gruß
Jens
Man sollte seine Werkzeuge kennen. Ansonsten haut man sich mit dem Hammer nur auf die Finger.

--
NetBeans Certified Engineer - Java Getriebe

daflowjoe
Beiträge: 8
Registriert: 12.09.2012, 22:42

Re: GUI Builder ActionListener

Beitrag von daflowjoe » 22.09.2012, 17:24

Ja das waere nett. Wuerde mich wirklich interessieren und anderen Entwicklern das Verstaendnis auch erleichtern ;)

In meinem Fall ist es z.B. ich habe eine Liste mit Buchungsobjekten in einer ArrayList als Model und eine Frameklasse als View. Im View habe ich jetzt eine Methode refresh(), welche die Daten bei Gelegenheit neu liest.
Ok meine Frameklasse implementiert jetzt den Propertychangelistener, Mein Model erbt von ObservablePropterties.
Ich uebergebe mit setData mein Model an die Frameklasse.
Dann melde ich mit mit addPropertyChangeListener bei dem Datenobjekt an. Dann bau ich in Models die put und gets ein, um quasi Events auszuloesen.
Ist das soweit richtig angewendet?
Wie fange das Event jetzt in meinen GUI Klassen bzl. PCL ab? Dort rufe ich ja dann danach einfach meine Methode refresh() auf richtig? Dann werden bei jedem put() im Model die Listenerklassen Events aufgerufen? Wieso wird ein get an die Parentklasse gereicht? man interessiert sich doch nur fuer Aenderungen und keine Lesezugriffe?!

Antworten