TreeModelEvents auslösen

Status
Nicht offen für weitere Antworten.

AlArenal

Top Contributor
Salut!

Ich hänge hier gerade mal wieder in einem Projekt. Und zwar habe ich mir mein eigenes Datenmodell (implements TreeModel) gestrickt. Eine Testroutine schiebt da Testdaten rein und es wird auch alles richtig angezeigt.

Spannend wird es nun beim interaktiven hinzufügen und entfernen von Daten. Mein Model beherbergt eine HashMap in der alle meine Objekte mit ihren IDs abgelegt sind. Es handelt sich um Instanzen eigener Klassen, die nicht von irgendwas abgeleitet sind.

Entferne ich nun ein Objekt (erst lösche ich die Refenzen, dann das Objekt in der HashMap) tut sich im Tree natürlich mal gar nichts, weil ich noch den passenden Event auslösen muss. Problem ist, dass ich mit den Parametern im Konstruktor nicht viel anfangen kann. Ich habe z.B. ad hoc keine Ahnung wie ich von einem meiner Objewkte den TreePath bestimmen sollte. Ich finde auch keine passenden Beispiele, weil alle immer DefaultMutableTreeNodes verwenden und da der Fall dann gleich anders aussieht..

Bin hier gerade etwas gefangen in Ideenlosigkeit...

Weiß einer ein Tutorial oder ein gutes Beispiel?
 
R

Roar

Gast
du musst an alle deine hinzugefügtn TreeModelListener events feuern.
wenn also ein node gelöscht wurde musst du von allen listenern treeNodesRemoved aufrufen, mit einem TreeModelEvent als parameter. dem TreeModelEvent übergibst du die parameter wie sie ausführlich in der dokumentations beschrieben sind.
 

AlArenal

Top Contributor
Diese Methoden haben ich schon (z.B. fireTreeNodesRemoved(TreeModelEvent e) ) , aber die Aufrufparameter des Events machen mir Kopfzerbrechen. Aus den Beschreibungen der Konstruktoren geht für mich nicht hervor wann welcher Konstruktor zu verwenden ist. Was ist der Unterschied zwischen TreeModelEvent(Object source, TreePath path, int[] childIndices, Object[] children) und TreeModelEvent(Object source, Object[] path, int[] childIndices, Object[] children) ? Und wie komme ich an den TreePath eines meiner Objekte? Und was ist the magic behind all diesen Parametern?

Mir fehlen da Beispiele zum Nachvollziehen. Mein Swing-Buch von Sun schweigt sich da auch aus und meine neuen Bücher sind noch unterwegs :(
 

AlArenal

Top Contributor
Ich sitze immernoch an diesem Scheiß-Problem, surfe die einschlägigen Foren bei Sun rauf und runter und google mich wund, aber komme nicht wirklich weiter. Viele lösen das Problem einfach, indem sie ein DefaultTreeModel und DefaultMutableTreeNode benutzen, aber das fällt für mich flach, weil es meine Anwendung ohne ENde verkomplizieren würde.

Problem ist einfach eine vernünftige Vorlage zu finden, wie man diese verdammten TreeModelEvents auslöst. Wenn ich mir den Quellcode vom DefaultTreeModel ansehe, bekomme ich Fragezeichen in die Augen und übernehme ich testeshalber Code, funzt der natürlich nicht (Anzeige ändert sich nicht; StackOverflowErrors, ...)...

Und dem Buchhändler wo mein Chef bestellt hat trete ich auch noch in den Arsch, weil der seit Wochen nen feuchten Dreck liefert.. grrrr.....
 
B

Beni

Gast
Am besten verwendest du den public TreeModelEvent(Object source, Object[] path, int[] childIndices, Object[] children) -Konstruktor.

So, ich hoffe mal ich labbere keinen quatsch zusammen...

Egal ob Childs hinzugefügt, entfernt oder nur verändert werden, der Konstruktor des TreeEvents bleibt derselbe, nur die Methode die bei den TreeModelListenern aufgerufen wird, wird anders gewhält (treeNodesRemove, Changed, ...).

Dieser Konstruktor hat 4 Parameter:
source Das "Objekt" das das Event abfeuert. Du kannst hier dasjenige Objekt einsetzen, in welchem die TreeModelListener registriert sind -> also nichts anderes als dein TreeModel

path
Das ist der Pfad zum Parent (!) der Knoten welche eingefügt oder gelöscht wurden.
Dieser Pfad geht "von oben nach unten", also an erster Stelle ist die Wurzel des Baumes, an zweiter Stelle ein Knoten aus der 2. Ebene des Baumes, ..., an letzter Stelle der Parent:

path[0] = root;
path[1] = Knoten aus Ebene 2;
path[2] = Knoten aus Ebene 3;
path[3] = Knoten aus Ebene 4;
path[4] = Der Parent derjenigen Knoten, welche hinzugefügt, entfernt oder verändert wurden. Im weiteren nenn ich diesen Knoten mal Parent.

childIndices
Angenommen beim Parent wurden zwei Kinder entfernt. Jeder Knoten in einem JTree verhält sich ja wie eine Liste (die Childs werden mit Indices angesprochen), von dem her hatten diese zwei Kinder bevor sie entfernt wurden einen eindeutigen Index.
Genau diese beiden Indices müssen hier übergeben werden.
Wichtig: beim Entfernen werden hier die Indices der Kinder vor der Entfernen-Aktion genommen
beim Einfügen werden hier die Indices der Kinder nach der Einfügen-Aktion genommen

children
Tja, und das sind die Knoten, welche entfernt, eingefügt oder verändert wurden.


Beispiel: Du hast folgenden Baum

Code:
'root'
 +- 'alpha'
 |   L '123'
 L- 'beta'
     + 'a'
     + 'b'
     L 'c'

Nun werden b und c entfernt.
Dann wird dein TreeModelEvent folgendermassen aufgebaut:
Code:
path = new Object[2];
path[0] = root;
path[1] = beta;

childIndices = new int[2];
childIndices[0] = 1; // "b"
childIndices[1] = 2; // "c"

childs = new Object[2];
childs[0] = b;
childs[1] = c;

event = new TreeMovelEvent( this, path, childIndices, childs );

Wie immer: ohne Gewähr :wink:
 

AlArenal

Top Contributor
Also zumindest das Löschen von Nodes funzt nun, alles andere habe ich noch nicht testen können. Nun habe ich aber eine weitere Denksportaufgabe:

Ich nutze ein eigenes TreeModel als zentrale Datenquelle. Um dieses Model herum gibt es mehrere weitere Models, die das zentrale Model als Datenquelle nutzen. So kann ich in unterschiedlichen JTrees unterschiedliche Sichtweisen (Filter) auf dieselben Daten reaisieren.

Für sich genommen funzt beides, nur in der Kombination funktioniert es nicht. Da fällt mir auch gerade nichts schlaues ein. *grübel*
 
B

Beni

Gast
Ich würde das so machen: Die Filter-Modelle registrieren TreeModelListener's beim zentralen TreeModel, und rechnen die Events dann auf ihre Indices (=angezeigte Teile) um.
 

AlArenal

Top Contributor
Sowas hatte ich mir auf dem Heimweg auch überlegt. Muss ich mir mal Gedanken machen, wenn ich wieder nüchtern bin....
 

AlArenal

Top Contributor
@beni:

Ich bin gerade noch bei der Planung und auf folgendes Problem gestoßen. Sagen wir mal wir haben neben dem zentralen TreeModel noch zwei FilterModels. Gehen wir weiter davon aus, dass die JTrees nie direkt das zentrale Model benutzen, sondern über die Filter gehen.

Nun nehmen wir an über Filter1 würde ein Node gelöscht. Dann müsste Filter1 an seine registrierten TreeModelEventListener entsprechende Events abgeben und das tatsächliche Löschen über das zentrale Model durchführen.

Daraufhin wirft das zentrale Model ja ebenfalls an seine Listener (also auch Filter2) entsprechende Events. Wie soll nun aber Filter2 an dessen registrierte Listener passend umgerechnete Events weiterleiten? Im zentralen Model ist ein Node gelöscht worden und Filter2 hat doch nun keine Möglichkeit mehr zu bestimmen welchen Index der Node in diesem Filter hatte?

*grübel*
 
B

Beni

Gast
AlArenal hat gesagt.:
Nun nehmen wir an über Filter1 würde ein Node gelöscht. Dann müsste Filter1 an seine registrierten TreeModelEventListener entsprechende Events abgeben und das tatsächliche Löschen über das zentrale Model durchführen.
Wenn Filter1 da zentrale Model abhört, muss er nicht selbst noch ein Event abschicken (das wird sonst irgendwie doppelt: Filter1 verschickt Event, zentrales Model verschickt Event woraufhin Filter1 nocheinmal ein Event verschickt). ???:L
(Oke, das kommt draufan wie du das schlussendlich genau implementierst, aber ich glaub es ist am einfachsten, wenn Filter1 erst ein Event verschickt, wenn es von der Zentrale ein Event bekommt).

Filter2 hat doch nun keine Möglichkeit mehr zu bestimmen welchen Index der Node in diesem Filter hatte?
Doch, hat er: wenn das zentrale Model die Events so aufbaut wie oben beschrieben, hat es die Indices in dem Event gespeichert. Filter2 kann nun diese Indices abrufen, und so den Aufbau des Baumes (ohne den Filter) rekonstruieren. Wenn aber der originale Baum rekonstruiert ist, ist es keine Kunst mehr die Indices umzurechnen.

Ein bisschen Pseudocode, wie man das Original rekonstruieren könnte:
Code:
public void nodesRemoved( TreeModelEvent e ){
  int[] indices = e.getChildIndices();
  Object[] children = e.getChildren();

  List nodes = ... // Liste der Knoten, welche jetzt (nach dem Entfernen) noch beim Parent registriert sind.

  // und jetzt die entfernten Children an der alten Position wieder einfügen
  for( int i = indices.length-1; i >= 0; i-- ){
    nodes.add( indices[i], children[i] );
  }

  // jetzt beschreibt nodes die Kinder des Parents, bevor ein paar entfernt wurden.

  // das Umrechnen funktioniert jetzt wie früher: Knoten abrufen, und index hochzählen, sollte ein Knoten angezeigt werden.
}
 

AlArenal

Top Contributor
Es funzt!

Meine Filter implementieren TreeModelListener und registrieren sich im ZentralModel. Die Löschanforderung für einen Node wird zum ZentralModel durchgereicht, welches den passenden Event auslöst. Diesen fangen die FilterModels ab und erzeugen den Path und den Index neu, entsprechend ihrer Sicht auf die Daten und generieren dann den TreeModelEvent für ihre Listener (JTrees).

Nun muss ich erstmal ne Runde Doku schreiben, damit das später auch mal wer anders rafft...
 

AlArenal

Top Contributor
Bin gerade beim nachträglichen Einfügen von Nodes:

Ich füge über den Filter ein, der das Ganze nach unten an das zentrale Model weiterreicht. Dazu ruft der Filter auch die fireTreeNodesInserted() vom zentralen Model auf.

Soweit funzt das, allerdings klappt der JTree bei seinem Refresh alle Äste ein, wenn er dann den neuen Node darstellt. Eigentlich hätte ich erwartet, dass die Anzeige halt nur um den neuen zusätzlichen Node erweitert wird.

Gibts da nen Trick?
 
B

Beni

Gast
Und das Filtermodel ruft dann auch treeNodesInserted auf? Die Angaben (Parent des neuen Childs etc) stimmen?
 

AlArenal

Top Contributor
Hatte gerade noch nen Dnekfehler, aber der Effekt ist noch da. Ich habe folgendes:

Pseudocode:

Code:
JTree.insertNode(node) {
  rootModel.fireTreeNodesInserted(convertForRootModel(TreeModelEvent));
}

RootModel.fireTreeNodesInserted(TreeModelEvent) {
  foreach (TreeModelEventListener) {
    treeModelListener.treeNodesIserted(TreeModelEvent);
  }
}

Filter.treeNodesInserted(TreeModelEvent) {
  fireTreeNodesInserted(convertForFilter(TreeModelEvent));
}

Was der Tree anzeigt ist grundsätzlich richtig, nur dampft er den Tree bis auf alles unterhalb des RootNodes ein und verliert auch die Selection. Als hätte ich ein neues Model geladen, was ich aber nicht tue.

Im Grunde benutze ich diegleiche Methode als wenn ein Node removed worden wäre, was die Umrechnung zwischen den Models angeht, nur das ich eben die passenden Methoden beim Listener aufrufe. Im Filter siehts am Ende so aus:

Code:
        // geänderten Event an eigene Listener schicken:
        fireTreeNodesInserted(
                new TreeModelEvent(
                        this,
                        getPathToRoot((FMEAInterface) getRoot(), (FMEAInterface) parent),
                        new int[] {indexHere},
                        new Object[] {insertedChild}
                )
        );
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
Juelin in javafx Event auslösen AWT, Swing, JavaFX & SWT 4
G Mouse Event in anderemm Event auslösen AWT, Swing, JavaFX & SWT 50
schoel27 Mehrere JButtons sollen das gleiche Event auslösen AWT, Swing, JavaFX & SWT 2
S ActionEvent Press Enter per Code auslösen AWT, Swing, JavaFX & SWT 22
L JButton durch Mausklick auslösen und Enter-Taste AWT, Swing, JavaFX & SWT 2
X Javafx button per enter auslösen AWT, Swing, JavaFX & SWT 5
G Swing Durch GlassPane auf Button klicken und ActionEvent auslösen AWT, Swing, JavaFX & SWT 0
R JButton durch Enter auslösen AWT, Swing, JavaFX & SWT 7
X Swing MouseEvent auslösen AWT, Swing, JavaFX & SWT 3
L ListSelectionListener durch Code auslösen AWT, Swing, JavaFX & SWT 3
T MouseEnteredEvent von verdeckten JPanel auslösen AWT, Swing, JavaFX & SWT 2
A Shift-Tab-Event auslösen AWT, Swing, JavaFX & SWT 5
M ActionListener mit code!!! auslösen AWT, Swing, JavaFX & SWT 3
V Swing Auslösen von zwei Events hintereinander AWT, Swing, JavaFX & SWT 4
M SWT SelectionEvent künstlich auslösen AWT, Swing, JavaFX & SWT 4
S SWT Bei Auslösen eines Buttones ein Textfeld generieren AWT, Swing, JavaFX & SWT 2
O Action Event auslösen bei unbekanntem JTextField AWT, Swing, JavaFX & SWT 3
E bei gedrückte Taste --> Bitte nur ein Event auslösen AWT, Swing, JavaFX & SWT 4
D Tastatur Shortcut auslösen bei FocusGained-Event AWT, Swing, JavaFX & SWT 2
P ActionListener auslösen AWT, Swing, JavaFX & SWT 6
S Bei SWT in einer Tabelle ein Event per Doppelklick auslösen? AWT, Swing, JavaFX & SWT 3
X MouseEvent selber auslösen AWT, Swing, JavaFX & SWT 12
A Mit der Combobox eine Action auslösen AWT, Swing, JavaFX & SWT 2
M JComboBox - Mittels FocusListener Event auslösen? AWT, Swing, JavaFX & SWT 4
T Java Runtime.exec per JButton auslösen -> Programm hängt AWT, Swing, JavaFX & SWT 10
bernd Jlist, aktion auslösen AWT, Swing, JavaFX & SWT 22
J Aktion bei Click auf Blatt auslösen AWT, Swing, JavaFX & SWT 6

Ähnliche Java Themen

Neue Themen


Oben