2015-07-02 2 views
1

У меня есть TreeTableView с элементами. Я хочу, чтобы этот пользователь увидел, что «стрелка» расширяется, даже если у элемента нет детей. Причина очень проста - ленивая нагрузка. Когда пользователь нажимает на стрелку, программа проверяет наличие возможных элементов (например, в БД). Если дети для этого предмета существуют, то они добавляются к элементу. Если они не существуют, «стрелка» должна исчезнуть. Как это сделать?JavaFX: TreeTableView и расширяющиеся элементы без детей

+0

Возможно, вы можете добавить фиктивные элементы без фактического содержимого в пустых элементах. Затем, когда пользователь нажимает стрелку, удалите фиктивный элемент и замените его загруженным содержимым из базы данных. –

+0

@RedRoboHood Я тоже думал об этом. Но, возможно, есть лучшее решение. –

+0

Не работает ли этот пример в [Javadocs for 'TreeItem'] (http://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TreeItem.html)? –

ответ

3

Javadocs for TreeItem показать пример, который в основном делает это. Вы можете переопределить методы isLeaf и getChildren для ленивого инстанцирования детей. Вот та же идея, адаптированная для TreeTableView:

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

import javafx.application.Application; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.collections.ObservableList; 
import javafx.event.Event; 
import javafx.scene.Scene; 
import javafx.scene.control.TreeItem; 
import javafx.scene.control.TreeTableColumn; 
import javafx.scene.control.TreeTableView; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 

public class LazyTreeTable extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     TreeTableView<Item> treeTable = new TreeTableView<>(); 
     TreeTableColumn<Item, String> nameCol = new TreeTableColumn<>("Name"); 
     nameCol.setCellValueFactory(cellData -> cellData.getValue().getValue().nameProperty()); 
     nameCol.setPrefWidth(250); 
     TreeTableColumn<Item, Number> valueCol = new TreeTableColumn<>("Value"); 
     valueCol.setCellValueFactory(cellData -> cellData.getValue().getValue().valueProperty()); 
     valueCol.setPrefWidth(150); 
     treeTable.getColumns().addAll(Arrays.asList(nameCol, valueCol)); 

     treeTable.setRoot(new ItemTreeNode(new Item(1))); 

     primaryStage.setScene(new Scene(new BorderPane(treeTable), 400, 600)); 
     primaryStage.show(); 
    } 

    public static class ItemTreeNode extends TreeItem<Item> { 
     private boolean childrenLoaded = false ; 

     public ItemTreeNode(Item value) { 
      super(value); 
     } 

     @Override 
     public boolean isLeaf() { 
      if (childrenLoaded) { 
       return getChildren().isEmpty() ; 
      } 
      return false ; 
//   return getChildren().isEmpty(); 
     } 

     @Override 
     public ObservableList<TreeItem<Item>> getChildren() { 
      if (childrenLoaded) { 
       return super.getChildren(); 
      } 

      childrenLoaded = true ; 
      if (getValue().getValue() < 100_000) { 
       List<TreeItem<Item>> children = new ArrayList<>(); 
       for (int i = 0 ; i < 10; i++) { 
        children.add(new ItemTreeNode(new Item(getValue().getValue() * 10 + i))); 
       } 
       super.getChildren().addAll(children); 
      } else { 
       // great big hack: 
       super.getChildren().add(null); 
       super.getChildren().clear(); 
      } 
      return super.getChildren() ; 
     } 
    } 

    public static class Item { 
     private IntegerProperty value = new SimpleIntegerProperty(); 
     private StringProperty name = new SimpleStringProperty(); 

     public Item(String name, int value) { 
      setName(name); 
      setValue(value); 
     } 

     public Item(int value) { 
      this(String.format("Item %,d", value), value); 
     } 

     public final IntegerProperty valueProperty() { 
      return this.value; 
     } 

     public final int getValue() { 
      return this.valueProperty().get(); 
     } 

     public final void setValue(final int value) { 
      this.valueProperty().set(value); 
     } 

     public final StringProperty nameProperty() { 
      return this.name; 
     } 

     public final java.lang.String getName() { 
      return this.nameProperty().get(); 
     } 

     public final void setName(final java.lang.String name) { 
      this.nameProperty().set(name); 
     } 


    } 

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

Я проверил пример для Javadocs. Однако это не 100%, что я ищу. Посмотрите, когда показан элемент isLeaf. Здесь мы возвращаем false (пользователь не нажал - мы не знаем). Когда пользователь нажимает логику, выполняется. Предположим - детей нет. Теперь мы можем вернуть true для метода isLeaf. Тем не менее, этот метод не указывается до тех пор, пока мы не закроем родительский элемент и т. Д. Как мы можем сделать метод javafx isLeaf, что-то вроде обновления и т. Д.? –

+0

Это будет сложно. Проблема заключается в том, что API для свойства 'leaf' в' TreeItem' был написан неправильно; 'leafProperty()' является 'final' и' isLeaf() 'не является: это должно было быть наоборот. Проблема в том, что если вы переопределите 'isLeaf', это больше не соответствует' leafProperty'; и нет никакого способа изменить значение 'leafProperty', кроме изменения значения дочернего списка или использования большого большого взлома (см. обновление). –

+0

Еще одна вещь, которую вы можете рассмотреть, - загрузить детей «на один уровень вниз». Если вы реализуете метод 'isLeaf()' так же, как 'return getChildren(). IsEmpty();', (и удаляете большой большой взлом), тогда дети будут загружаться сразу же после отображения узла (а не как скоро по мере расширения узла). Это дает немного меньше лености, но позволяет «проверять лист», как только отображается узел. –

Смежные вопросы