Пользовательский вид дерева JavaFX со списком

#javafx #combobox #treeview

#javafx #выпадающий список #древовидный вид

Вопрос:

Я пытаюсь создать древовидный просмотр, который будет иметь на каждой ветке и лист со списком, кнопку «добавить дочерний элемент» и кнопку «удалить дочерний элемент». Вот мой код

 package example;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 *
 * @author me
 */
public class Example extends Application {
  
String[] companyNames = new String[10];     
    
    
    
    @Override
    public void start(Stage primaryStage) {
        
   companyNames[0]="FORD";    
   companyNames[1]="MG";
   companyNames[2]="LADA";
   companyNames[3]="BMW";
   companyNames[4]="KIA";
   companyNames[5]="HYUNDAI";
   companyNames[6]="AUDI";
   companyNames[7]="MERCEDES";
   companyNames[8]="DACIA";   
   companyNames[9]="TOYOTA";   
   
   
   final TreeItem<String> treeRootItem = new TreeItem<>("Root");
   final TreeView<String> treeView = new TreeView<>(treeRootItem); 
    
   treeRootItem.setExpanded(true);    
   treeView.setCellFactory(e -> new CustomCell()); 
   
   VBox mainVBox = new VBox();
   
   mainVBox.getChildren().add(treeView);     
    
   Scene scene1 = new Scene(mainVBox,1600,600);
   primaryStage.setScene(scene1);
   primaryStage.show();
   primaryStage.centerOnScreen();      

    }    
    
    //function custom TreeCell CustomCell 
    class CustomCell extends TreeCell<String> {
    @Override
    protected void updateItem(String item, boolean empty) 
    
    {

    ComboBox companiesComboBox = new ComboBox();
    Button addChildButton = new Button("Add Child");
    Button removeButton = new Button("Remove Child");

    super.updateItem(item, empty);

    if (isEmpty()) {
                    setGraphic(null);
                    setText(null);
                    } 
    else {

          HBox cellBox = new HBox(10);

          if (item.equals("Root"))
          {
            cellBox.getChildren().addAll(companiesComboBox,addChildButton);
          }
        
          else  cellBox.getChildren().addAll(companiesComboBox,addChildButton,removeButton);

          setGraphic(cellBox);
          setText(null);
          }
        
        
    companiesComboBox.getItems().addAll((Object[]) companyNames);
        

    addChildButton.setOnAction(new EventHandler<ActionEvent>() {
    @Override public void handle(ActionEvent e) {
        
    String selection=companiesComboBox.getSelectionModel().getSelectedItem().toString();
    TreeItem<String> childNode1 = new TreeItem<>("Child Node");
    getTreeItem().getChildren().add(childNode1);

    }});   
              
    removeButton.setOnAction(value ->  { 
    //somehow i will remove the leaf/branch    
    });   
        
        }
    }
    
    public static void main(String[] args) {
        launch(args);
    }
    
}
 

(Как указала Александра, в моем предыдущем посте у меня было много неправильных соглашений об именах Java, надеюсь, я исправил это сейчас.
Прошу прощения, что я удалил свой предыдущий пост, но он был не по теме со многими ошибками, поэтому я решил провести небольшое исследование, как сделать сообщение с лучшим кодом и более конкретным без ошибок, и вернуться через несколько дней.Я надеюсь, что теперь это презентабельно.)
Проблема, с которой я сталкиваюсь, заключается в том, что когда я добавляю нового дочернего элемента, дерево отверстий теряет выбор со списком.
Вот изображение запущенного проекта https://ibb.co/8MVDqhX
Любая помощь / предложение будут оценены

ОБНОВЛЕНИЕ: после ответа Slaw я попытался создать класс модели с именем SelectedCompanyClass

 package example;

import javafx.beans.property.StringProperty;

/**
 *
 * @author me
 */
public class SelectedCompanyClass {
    

    public String companyNameString;

    public SelectedCompanyClass(String companyNameString) {
        this.companyNameString = companyNameString;
    }
        
}
 

И я изменил свой основной класс следующим образом

 package example;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 *
 * @author me
 */
public class Example extends Application {
  
String[] companyNames = new String[10];     
int x=0;        
SelectedCompanyClass SelectedCompanyClass1;   


    @Override
    public void start(Stage primaryStage) {
     
    this.SelectedCompanyClass1 = new SelectedCompanyClass("root");
        
   companyNames[0]="FORD";    
   companyNames[1]="MG";
   companyNames[2]="LADA";
   companyNames[3]="BMW";
   companyNames[4]="KIA";
   companyNames[5]="HYUNDAI";
   companyNames[6]="AUDI";
   companyNames[7]="MERCEDES";
   companyNames[8]="DACIA";   
   companyNames[9]="TOYOTA";   
   
   
   final TreeItem<SelectedCompanyClass> treeRootItem = new TreeItem<>(SelectedCompanyClass1);
   final TreeView<SelectedCompanyClass> treeView = new TreeView<>(treeRootItem); 
   
   treeRootItem.setExpanded(true);    
   treeView.setCellFactory(e -> new CustomCell()); 
   
   VBox mainVBox = new VBox();
   
   mainVBox.getChildren().add(treeView);     
    
   Scene scene1 = new Scene(mainVBox,1600,600);
   primaryStage.setScene(scene1);
   primaryStage.show();
   primaryStage.centerOnScreen();      
   System.out.println("Start runs");
   
    }    
    

    class CustomCell extends TreeCell<SelectedCompanyClass> {
    
    protected void updateItem(SelectedCompanyClass SelectedCompanyClass1, boolean empty) 
    
    {

    ComboBox companiesComboBox = new ComboBox();
    Button addChildButton = new Button("Add Child");
    Button removeButton = new Button("Remove Child");

    super.updateItem(SelectedCompanyClass1,empty);
    
    if (isEmpty()) {
                    setGraphic(null);
                    setText(null);
                    } 
    else {

          HBox cellHBox = new HBox();

                    if (SelectedCompanyClass1!=null)
          {  
          if (SelectedCompanyClass1.companyNameString.equals("Root"))
          {
            cellHBox.getChildren().addAll(companiesComboBox,addChildButton);
          
          }
          else  cellHBox.getChildren().addAll(companiesComboBox,addChildButton,removeButton);
          companiesComboBox.getSelectionModel().select(SelectedCompanyClass1.companyNameString);
          }
          setGraphic(cellHBox);
          setText(null);
          
          }
        

    companiesComboBox.getItems().addAll((Object[]) companyNames);
        

    addChildButton.setOnAction(new EventHandler<ActionEvent>() {
    @Override public void handle(ActionEvent e) {
    String selection="none";     

    SelectedCompanyClass SelectedCompanyClass2 = new SelectedCompanyClass(selection);
    
    if (companiesComboBox.getSelectionModel().getSelectedItem().toString()!=null) {
        selection=companiesComboBox.getSelectionModel().getSelectedItem().toString();
        SelectedCompanyClass2.companyNameString=selection;
    }


    TreeItem<SelectedCompanyClass> childNode2 = new TreeItem<>(SelectedCompanyClass2);
    
    getTreeItem().getChildren().add(childNode2);
    childNode2.setExpanded(true);
    }});   
   
    removeButton.setOnAction(value ->  { 
    //somehow i will remove the leaf/branch    
    });   
    }
    
 
    }
    
    public static void main(String[] args) {
        launch(args);
    }
    
    
}
 

Теперь, благодаря Slaw, я добился прогресса и создаю новые объекты TreeItem как дочерние, но родительский узел теряет свой выбор в списке

ОБНОВЛЕНИЕ 2: после полезных предложений я, наконец, сделал это, вот код
Код класса модели

 package example;

import javafx.beans.property.StringProperty;


public class SelectedCompanyClass {
String companyNameString = new String();    

    public SelectedCompanyClass() {
    companyNameString="Choose";
        
    }
}
 

и основной код

 package example;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 *
 * @author me
 */
public class Example extends Application {
  
String[] companyNames = new String[10];     
int x=0;        


    @Override
    public void start(Stage primaryStage) {
     
   SelectedCompanyClass SelectedCompanyClass1 = new SelectedCompanyClass();
        
   companyNames[0]="FORD";    
   companyNames[1]="MG";
   companyNames[2]="LADA";
   companyNames[3]="BMW";
   companyNames[4]="KIA";
   companyNames[5]="HYUNDAI";
   companyNames[6]="AUDI";
   companyNames[7]="MERCEDES";
   companyNames[8]="DACIA";   
   companyNames[9]="TOYOTA";   
   
   
   final TreeItem<SelectedCompanyClass> treeRootItem = new TreeItem<>(SelectedCompanyClass1);
   final TreeView<SelectedCompanyClass> treeView = new TreeView<>(treeRootItem); 
   
   treeRootItem.setExpanded(true);    
   treeView.setCellFactory(e -> new CustomCell()); 
   
   VBox mainVBox = new VBox();
   
   mainVBox.getChildren().add(treeView);     
    
   Scene scene1 = new Scene(mainVBox,1600,600);
   primaryStage.setScene(scene1);
   primaryStage.show();
   primaryStage.centerOnScreen();      
   System.out.println("Start runs");
   
   

   
    }    
    

    class CustomCell extends TreeCell<SelectedCompanyClass> {
    
    protected void updateItem(SelectedCompanyClass SelectedCompanyClass1, boolean empty) 
    
    {

    ComboBox companiesComboBox = new ComboBox();
    Button addChildButton = new Button("Add Child");
    Button removeButton = new Button("Remove");
    Label objectLabel = new Label();

    
        companiesComboBox.valueProperty().addListener((obs, oldValue, newValue) -> {
        SelectedCompanyClass1.companyNameString=newValue.toString();
        });   
   
    
    
    super.updateItem(SelectedCompanyClass1,empty);
    
    if (isEmpty()) {
                    setGraphic(null);
                    setText(null);
                    } 
    else {

          HBox cellHBox = new HBox();

                    if (SelectedCompanyClass1!=null)
          {  
          cellHBox.getChildren().addAll(companiesComboBox,addChildButton,removeButton,objectLabel);
          companiesComboBox.getSelectionModel().select(SelectedCompanyClass1.companyNameString);
          }
          setGraphic(cellHBox);
          setText(null);
          
          }
        

    companiesComboBox.getItems().addAll((Object[]) companyNames);
        

        

    addChildButton.setOnAction(new EventHandler<ActionEvent>() {
    @Override public void handle(ActionEvent e) {
    String selection="none";     

    SelectedCompanyClass SelectedCompanyClass2 = new SelectedCompanyClass();
    
    TreeItem<SelectedCompanyClass> childNode2 = new TreeItem<>(SelectedCompanyClass2);
    getTreeItem().getChildren().add(childNode2);
    childNode2.setExpanded(true);


       companiesComboBox.valueProperty().addListener((obs, oldValue, newValue) -> {
       SelectedCompanyClass2.companyNameString=newValue.toString();
        }); 

    
    }});   
   
    removeButton.setOnAction(value ->  { 
    //somehow i will remove the leaf/branch    
    });   
    }
    

    }
    
    public static void main(String[] args) {
        launch(args);
    }
    
    
}
 

С наилучшими пожеланиями всем

Комментарии:

1. Я не анализировал ваш код подробно, но моя интуиция подсказывает мне, что проблема в том, что у вас нет модели . Поскольку у вас нет модели, вы используете представление для поддержания состояния, а это бесполезно. Создайте модель и просто TreeView<YourModel> отобразите состояние указанной модели. Затем взаимодействие с деревом обновляет модель , и дерево отслеживает модель на предмет изменений, чтобы быть в курсе последних событий.

2. Спасибо за ваш любезный ответ, Slaw, я рассмотрю его

3. Не создавайте новое поле со списком в updateItem() ; создайте один раз для каждого экземпляра ячейки (например, в конструкторе) и установите его выбранное значение updateItem() . Но это не имеет для меня абсолютно никакого смысла: в каком смысле одна компания является дочерней компанией другой компании? Кроме того, пожалуйста, не удаляйте и, по сути, не публикуйте один и тот же вопрос; вы должны отредактировать свой старый вопрос.

4. Да, спасибо, James_D я пытался добавить конструктор, но у меня не получилось заставить его работать

5. Спасибо, Клеопатра, я допустил ошибку в именовании; я прочитал несколько статей и попытался быть корректным в своем коде