带有网格面板的 Javafx treeview 细胞工厂

Javafx treeview cell factory with gridpane

我有一个 TreeView<GridPane> 并且 GridPane 包含多个节点,例如按钮和标签。 GridPane 内的节点数量各不相同。

我需要细胞工厂来获取 MouseEntered 事件,但是当我使用下面的代码时,没有显示任何内容。

我当前的代码如下所示:

treeView.setCellFactory(tv -> {
    TreeCell<GridPane> cell = new TreeCell<GridPane>() {
        @Override
        protected void updateItem(GridPane item, boolean empty) {
            super.updateItem(item, empty);
        }
    };

    cell.setOnMouseEntered(e -> {
        //TODO
    });

    return cell ;
});

我知道 updateItem 方法需要修改,但我不知道如何修改,因为 GridPane 中的节点数不同。

编辑 这是 类.

TreeController.java:

public class TreeController {

    private TreeItem<GridPane> rootItem;
    private int hgap = 5;

    @FXML private TreeView<GridPane> treeView;

    @FXML
    private void initialize() {

        GridPane gp = new GridPane();
        gp.add(new Label("Label1"), 0, 0);
        gp.getColumnConstraints().add(0, new ColumnConstraints());
        gp.getColumnConstraints().get(0).setHgrow(Priority.NEVER);

        Button cond = new Button("button");
        gp.add(cond, 1, 0);
        gp.getColumnConstraints().add(1, new ColumnConstraints());
        gp.getColumnConstraints().get(1).setHgrow(Priority.NEVER);


        gp.add(new Label("Label2"), 2, 0);
        gp.getColumnConstraints().add(2, new ColumnConstraints());
        gp.getColumnConstraints().get(2).setHgrow(Priority.ALWAYS);

        Button btnAdd = new Button("Add");
        gp.add(btnAdd, 3, 0);
        gp.setHgap(hgap);

        rootItem = new TreeItem<GridPane>(gp);
        rootItem.setExpanded(true);

        treeView.setRoot(rootItem);

        rootItem.getChildren().add(new TreeItem<GridPane>(createGridRow("Age", false)));
        rootItem.getChildren().add(new TreeItem<GridPane>(createGridRow("Person", true)));

        /*
        treeView.setCellFactory(tv -> {
            TreeCell<GridPane> cell = new TreeCell<GridPane>() {
                @Override
                protected void updateItem(GridPane item, boolean empty) {
                    super.updateItem(item, empty);
                }
            };

            cell.setOnMouseEntered(e -> {
                System.out.println("changed cell");
            });

            return cell ;
        });
        */
    }

    private GridPane createGridRow(String selectedCol, Boolean showAddButton) {
        int index = 0;
        GridPane gp = new GridPane();

        Button columnName = new Button(selectedCol);
        gp.add(columnName, index, 0);
        gp.getColumnConstraints().add(index, new ColumnConstraints());
        gp.getColumnConstraints().get(index).setHgrow(Priority.NEVER);
        index++;

        Button condition = new Button("greater than");
        gp.add(condition, index, 0);
        gp.getColumnConstraints().add(index, new ColumnConstraints());
        gp.getColumnConstraints().get(index).setHgrow(Priority.NEVER);
        index++;


        Button value = new Button("[enter value]");
        gp.add(value, index, 0);
        gp.getColumnConstraints().add(index, new ColumnConstraints());
        gp.getColumnConstraints().get(index).setHgrow(Priority.ALWAYS);
        index++;

        if (showAddButton) {
            Button btnAdd = new Button("Add");
            gp.add(btnAdd, index, 0);
            gp.getColumnConstraints().add(index, new ColumnConstraints());
            gp.getColumnConstraints().get(index).setHgrow(Priority.NEVER);
            index++;
        }

        gp.setHgap(hgap);

        return gp;
    }

}

MainClass.java:

public class MainClass extends Application{

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

    @Override
    public void start(Stage stage) {
        Parent root;
        try {
            TreeController controller = new TreeController();

            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("TreeController.fxml"));
            fxmlLoader.setController(controller);
            root = fxmlLoader.load();

            Scene scene = new Scene(root, 600, 500);

            stage.setMinHeight(400);
            stage.setMinWidth(500);
            stage.setTitle("TreeController");
            stage.setScene(scene);
            stage.setResizable(true);
            stage.show();
        } catch (IOException e) {
            e.printStackTrace();
        };    
    }

    @Override
    public void stop() {
        System.exit(0);
    }

}

TreeController.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TreeView?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0"     prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.161" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <ScrollPane fitToHeight="true" fitToWidth="true" layoutX="155.0" layoutY="111.0" prefHeight="200.0" prefWidth="200.0"     AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="20.0">
         <content>
            <TreeView fx:id="treeView" prefHeight="200.0" prefWidth="200.0" />
         </content>
      </ScrollPane>
   </children>
</AnchorPane>

这是一个相当简单但综合的例子。分析之后,您应该能够实施您的解决方案。

import javafx.application.Application;
import javafx.scene.Scene;
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.VBox;
import javafx.stage.Stage;

public class TreeViewCellApp extends Application {

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

    @Override
    public void start(Stage stage) throws Exception {
        TreeItem<Employee> leaf1Item = new TreeItem<Employee>(new Employee("Anne Burnes", "Employee"));
        TreeItem<Employee> leaf2Item = new TreeItem<Employee>(new Employee("Ronan Jackson", "Employee"));

        TreeItem<Employee> rootItem = new TreeItem<Employee>(new Employee("Jack Shields", "Head"));
        rootItem.getChildren().add(leaf1Item);
        rootItem.getChildren().add(leaf2Item);

        Label label = new Label();

        TreeView<Employee> treeView = new TreeView<>(rootItem);
        treeView.setCellFactory(param -> new TreeCell<Employee>() {
            @Override
            protected void updateItem(Employee employee, boolean empty) {
                super.updateItem(employee, empty);
                if (employee == null || empty) {
                    setGraphic(null);
                } else {
                    EmployeeControl employeeControl = new EmployeeControl(employee);
                    employeeControl.setOnMouseClicked(mouseEvent -> label.setText(employee.getName()));
                    setGraphic(employeeControl);
                }
            }
        });

        VBox vBox = new VBox(label, treeView);

        stage.setScene(new Scene(vBox));
        stage.show();
    }
}

class Employee {

    private final String name;
    private final String capacity;

    public Employee(String name, String capacity) {
        this.name = name;
        this.capacity = capacity;
    }

    public String getName() {
        return name;
    }

    public String getCapacity() {
        return capacity;
    }
}

class EmployeeControl extends HBox {

    private final Label nameLabel = new Label();
    private final Label capacityLabel = new Label();

    {
        getChildren().addAll(nameLabel, capacityLabel);
    }

    public EmployeeControl(Employee employee) {
        nameLabel.setText(employee.getName());
        capacityLabel.setText(employee.getCapacity());
    }
}