ich bastele mit JavaFX einen TreeView. Die einzenen TreeItems sollen editierbare Strings sein.
Ich habe erstmal mit TreeItem<String> angefangen, um die Grundstrukturen zu erlernen. Ich frage bei Druck auf einen Button das ausgewählte Item ab und erledige die zugehörigen Aufgaben wie Knoten nach oben schieben oder die Tiefe eines Knoten verändern.
Da alles funktioniert, bin ich jetzt bei TreeItem<TextField> und muss feststellen, dass bei Auswahl eines Knotens mit der Maus, das Textfeld zwar den Fokus erhält und in den Edit-Modus geht, das SelectedItem des Baumes aber null bleibt.
Warum denn das?
Wie muss ich denn die Baumansicht aufbauen, dass die Knotentexte editierbar sind und aber auch das Auswählen registriert und entsprechend das SelectedItem gesetzt wird?
Ich bin bissl überrascht, dass das nicht geht. Die Baumansicht ist der Inhalt eines Tabs in einem TabPanel und ich agiere dabei voll mit Code Behind, da Tab- und Knotenanzahl der darzustellenden Bäume unterschiedlich und auch dynamisch sind.
Mal schauen, was ChatGPT meint (alle Antworten sind von ChatGPT - unkorrigiert).
1. zu "Warum denn das?"
Das liegt daran, dass ein TreeItem<TextField> ein anderes equals()-Verhalten aufweist als ein TreeItem<String>. Wenn Sie ein TreeItem<String>-Objekt mit einem anderen vergleichen, wird der Inhalt der String-Objekte verglichen. Wenn Sie jedoch ein TreeItem<TextField>-Objekt mit einem anderen vergleichen, wird die Speicheradresse des Objekts verglichen.
Wenn Sie also ein TreeItem<TextField>-Objekt mit einem anderen vergleichen möchten, müssen Sie sicherstellen, dass die beiden Objekte auf die gleiche Speicheradresse verweisen. Dies kann durch Überschreiben der equals()-Methode des TreeItem<TextField>-Objekts erreicht werden.
Ein weiterer möglicher Ansatz ist, den TextField-Inhalt beim Klicken auf ein TreeItem<TextField>-Objekt in ein temporäres TreeItem<String>-Objekt zu kopieren und dieses temporäre Objekt auszuwählen. Auf diese Weise können Sie sicherstellen, dass der equals()-Vergleich ordnungsgemäß funktioniert.
Ich hoffe, das hilft Ihnen weiter!
2. Wie muss ich denn die Baumansicht aufbauen, dass die Knotentexte editierbar sind und aber auch das Auswählen registriert und entsprechend das SelectedItem gesetzt wird?
Um editierbare Knotentexte in Ihrem TreeView zu ermöglichen und gleichzeitig das Auswählen von Knoten zu registrieren, können Sie die TreeView- und TreeItem-Klassen von JavaFX verwenden.
Sie können den TreeItem-Konstruktor verwenden, der einen TextField als Parameter akzeptiert, um ein editierbares TreeItem-Objekt zu erstellen. Wenn der Benutzer den Text im TextField ändert, wird auch der Text des TreeItem geändert.
Um das Auswählen von Knoten zu registrieren, können Sie einen Listener auf die selectionProperty() des TreeView setzen. Der Listener wird aufgerufen, wenn ein Knoten ausgewählt wird, und Sie können das ausgewählte TreeItem aus der selectedItemProperty() des TreeView abrufen.
Hier ist ein Beispielcode, der Ihnen den grundlegenden Ansatz zeigen soll:
Java:
TreeView<String> treeView =newTreeView<>();// Baumstruktur aufbauenTreeItem<String> root =newTreeItem<>("Root");
root.setExpanded(true);TreeItem<String> child1 =newTreeItem<>("Child 1");
root.getChildren().add(child1);TreeItem<String> child2 =newTreeItem<>("Child 2");
root.getChildren().add(child2);
treeView.setRoot(root);// TreeView-Selection registrieren
treeView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue)->{if(newValue !=null){System.out.println("Selected: "+ newValue.getValue());}});// Editierbare TreeItems erstellenTreeItem<String> editableItem =newTreeItem<>("Editable Node");
editableItem.setGraphic(newTextField(editableItem.getValue()));
editableItem.getValue();// gibt den Text des TreeItems zurück
editableItem.getValue();// gibt das TextField-Objekt zurück
child1.getChildren().add(editableItem);
In diesem Beispiel wird ein TreeView-Objekt erstellt, dem ein Wurzel-TreeItem-Objekt hinzugefügt wird. Dann werden zwei weitere TreeItem-Objekte als Kinder des Wurzel-TreeItems hinzugefügt.
Dann wird ein editierbares TreeItem-Objekt erstellt, indem ein TextField-Objekt als Grafik des TreeItems gesetzt wird. Dieses TreeItem wird als Kind des ersten Kind-TreeItems hinzugefügt.
Schließlich wird ein Listener auf die selectedItemProperty() des TreeView gesetzt, um das ausgewählte TreeItem zu registrieren. Wenn der Benutzer ein TreeItem auswählt, wird der Name des Knotens in der Konsole ausgegeben.
Ich hoffe, das hilft Ihnen weiter!
3. zu "Was übersehe ich"?
Es tut mir leid, wenn meine vorherige Antwort nicht direkt auf Ihre Anforderungen zutraf. Es ist tatsächlich möglich, die Baumansicht mit editierbaren Knotentexten zu erstellen und gleichzeitig das Auswählen von Knoten zu registrieren. Hier ist ein Beispielcode, der Ihnen helfen soll:
Java:
TreeView<String> treeView =newTreeView<>();// Baumstruktur aufbauenTreeItem<String> root =newTreeItem<>("Root");
root.setExpanded(true);TreeItem<String> child1 =newTreeItem<>("Child 1");
root.getChildren().add(child1);TreeItem<String> child2 =newTreeItem<>("Child 2");
root.getChildren().add(child2);
treeView.setRoot(root);// TreeView-Selection registrieren
treeView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue)->{if(newValue !=null){System.out.println("Selected: "+ newValue.getValue());}});// Editierbare TreeItems erstellenTreeItem<String> editableItem =newTreeItem<>("Editable Node");
editableItem.setGraphic(newTextField(editableItem.getValue()));
editableItem.getValue();// gibt den Text des TreeItems zurück
editableItem.getValue();// gibt das TextField-Objekt zurück
child1.getChildren().add(editableItem);
In diesem Beispiel wird ein TreeView-Objekt erstellt und ein Wurzel-TreeItem-Objekt hinzugefügt. Dann werden zwei weitere TreeItem-Objekte als Kinder des Wurzel-TreeItems hinzugefügt.
Als Nächstes wird ein editierbares TreeItem-Objekt erstellt, indem ein TextField-Objekt als Grafik des TreeItems gesetzt wird. Das TreeItem wird als Kind des ersten Kind-TreeItems hinzugefügt.
Schließlich wird ein Listener auf die selectedItemProperty() des TreeView gesetzt, um das ausgewählte TreeItem zu registrieren. Wenn der Benutzer ein TreeItem auswählt, wird der Name des Knotens in der Konsole ausgegeben.
Ich hoffe, das hilft Ihnen weiter! Wenn Sie weitere Fragen haben, stehe ich gerne zur Verfügung.
<Ironie>
hm, net schlecht. Forum ade, willkommen chatGPT.
</Ironie>
Die Antwort scheint mir nicht korrekt, so die Kommentare zu den Zeilen 25 und 26. Gleicher Code aber unterschiedliche Erklärungen zum Verhalten.
Auch ob der Hinweis auf equals zielführend ist ? Eigentlich sind hier keine zwei unterschiedliche Instanzen im Spiel, oder? Es geht doch darum, dass nach der Auswahl eines Knoten die Eigenschaft SelectedItem nicht gesetzt wird. Dazu wird keine zweite Instanz benötigt. Ich wüsste auch nicht wozu da was verglichen werden sollte.
Ich wüsste nicht, was ich da für Code posten sollte, sry! Oder anders ausgedrückt, wie das hilfreich sein sollte.
die folgende Routine erzeugt eine Baumansicht. Lasse ich die Baumansicht anzeigen und wähle einen Eintrag aus, wird SelectedItem des Baumes nicht gesetzt und bleibt null. Mache is das gleiche aber anstatt mit TextField mit String, wird SelectedItem gesetzt.
Java:
privatevoidinitfortest(){TreeItem root =newTreeItem<TextField>(newTextField("Wurzel"));for(int i =0; i <10;++i){
root.getChildren().add(newTreeItem<TextField>(newTextField(String.format("Kind %04d", i))));}var i =0;for(var a : root.getChildren()){((TreeItem<TextField>) a).getChildren().add(newTreeItem<TextField>(newTextField(String.format("Enkel %4d", i++))));}this.setRoot(root);this.setShowRoot(false);}
Das war's schon. Mehr kann ich nicht zeigen, weil es mehr nicht gibt.
Das hängt vermutlich einfach damit zusammen, wie Du das Item wählst. Klickst Du in das Textfeld wird der Knoten nicht gewählt, klickst Du etwas links daneben, sieht es so aus:
Und dann wird auch korrekterweise auch
angezeigt.
Code dazu:
Java:
publicclassAppextendsApplication{@Overridepublicvoidstart(Stage stage){TreeItem<TextField> root =newTreeItem<>(newTextField("Wurzel"));for(int i =0; i <10;++i){
root.getChildren().add(newTreeItem<TextField>(newTextField(String.format("Kind %04d", i))));}int i =0;for(var a : root.getChildren()){((TreeItem<TextField>) a).getChildren().add(newTreeItem<TextField>(newTextField(String.format("Enkel %4d", i++))));}TreeView<TextField> treeView =newTreeView<>(root);
treeView.setShowRoot(false);Button button =newButton("Show");
button.setOnAction(eh ->{TreeItem<TextField> selectedItem = treeView.getSelectionModel().getSelectedItem();String text = selectedItem ==null?"Nichts gewählt":"Text: "+ selectedItem.getValue().getText();Alert alert =newAlert(INFORMATION);
alert.setContentText(text);
alert.showAndWait();});ScrollPane scrollable =newScrollPane(treeView);VBox content =newVBox(scrollable, button);var scene =newScene(content,640,480);
stage.setScene(scene);
stage.show();}publicstaticvoidmain(String[] args){launch();}}
ah, das hatte ich ausprobiert. Anscheinend hab ich dabei nie den richtigen Spot erwischt. * ärger *
Jetzt muss ich ausbaldovern, wie ich das hinbiegen kann, dass ich das Auswählen, d.h. den Erhalt des Fokus beim Textfeld abfangen und des SelectedItem wohl per Hand setzen kann.
Geht das dann über das zugehörige TextCell? Ich habe da noch nie nix mit gemacht.