2016-04-13

JavaFX: TreeView と CheckBoxTreeItem

JavaFX の TreeView にポップアップ・メニュー (ContextMenu) を表示するサンプルを以前紹介しましたが [1]、さらにチェックボックスをつける用途が出てきたので、まずは前述のサンプルをベースにテストをしました。まだ無駄が残っていますが、当初予定していた機能を実装できましたので紹介します。更に検討を加えた結果、補足・修正を加えるかもしれませんが、あらかじめご了承ください。

実行例

今回のサンプルは少々ソースが長くなるため、最初に実行例を示します。

にんじんのチェックボックスが 'false' から 'true' に変更されました。
なすのチェックボックスが 'false' から 'true' に変更されました。
とまとのチェックボックスが 'false' から 'true' に変更されました。
「とまと」が選択されました。

ソース

動作環境は次の通りです。

  • OS: Fedora 23 (x86_64)
  • Java: jdk1.8.0_77-1.8.0_77-fcs.x86_64 (Oracle)
  • IDE: NetBeans IDE 8.1
リスト:Sample_TreeView3.java 
package sample_treeview3;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.cell.CheckBoxTreeCell;
import static javafx.application.Application.launch;

public class Sample_TreeView3 extends Application {

    Image CAROT = new Image(getClass().getResource("carot.png").toString());
    Image EGGPLANT = new Image(getClass().getResource("eggplant.png").toString());
    Image TOMATO = new Image(getClass().getResource("tomato.png").toString());
    Image APPLE = new Image(getClass().getResource("apple.png").toString());
    Image GRAPE = new Image(getClass().getResource("grape.png").toString());
    Image BANANA = new Image(getClass().getResource("banana.png").toString());

    TreeView<String> tree;

    @Override
    public void start(Stage primaryStage) {

        TreeItem<String> top = new TreeItem<>("root");

        TreeItem<String> nodeItemA = new TreeItem<>("野菜");
        addNode(top, nodeItemA);
        nodeItemA.setExpanded(true);
        TreeItem<String> nodeItemB = new TreeItem<>("果物");
        addNode(top, nodeItemB);
        nodeItemB.setExpanded(true);

        TreeLeaf<String> nodeItemA1 = new TreeLeaf<>("にんじん", new ImageView(CAROT));
        TreeLeafListener(nodeItemA1);
        addNode(nodeItemA, nodeItemA1);
        TreeLeaf<String> nodeItemA2 = new TreeLeaf<>("なす", new ImageView(EGGPLANT));
        TreeLeafListener(nodeItemA2);
        addNode(nodeItemA, nodeItemA2);
        TreeLeaf<String> nodeItemA3 = new TreeLeaf<>("とまと", new ImageView(TOMATO));
        TreeLeafListener(nodeItemA3);
        addNode(nodeItemA, nodeItemA3);

        TreeLeaf<String> nodeItemB1 = new TreeLeaf<>("りんご", new ImageView(APPLE));
        TreeLeafListener(nodeItemB1);
        addNode(nodeItemB, nodeItemB1);
        TreeLeaf<String> nodeItemB2 = new TreeLeaf<>("ぶどう", new ImageView(GRAPE));
        TreeLeafListener(nodeItemB2);
        addNode(nodeItemB, nodeItemB2);
        TreeLeaf<String> nodeItemB3 = new TreeLeaf<>("ばなな", new ImageView(BANANA));
        TreeLeafListener(nodeItemB3);
        addNode(nodeItemB, nodeItemB3);

        tree = new TreeView<>(top);
        tree.setShowRoot(false);
        tree.setCellFactory((TreeView<String> p) -> new TreeCellImpl());

        StackPane root = new StackPane();
        root.getChildren().add(tree);

        Scene scene = new Scene(root, 200, 300);

        primaryStage.setTitle(getClass().getSimpleName());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    void TreeLeafListener(TreeLeaf<String> item) {
        item.selectedProperty().addListener((ObservableValue<? extends Boolean> obs, Boolean oldVal, Boolean newVal) -> {
            System.out.println(item.getValue() + "のチェックボックスが '" + oldVal + "' から '" + newVal + "' に変更されました。");
        });
    }

    void addNode(TreeItem<String> parent, TreeItem<String> child) {
        parent.getChildren().add(child);
    }

    class TreeLeaf<T> extends CheckBoxTreeItem<T> {

        public TreeLeaf(final T value) {
            super(value);
        }

        public TreeLeaf(final T value, final Node graphic) {
            super(value, graphic);
        }

        public ContextMenu getMenu() {
            ContextMenu popup = new ContextMenu();
            MenuItem menuItem = new MenuItem("処理");
            menuItem.setOnAction((ActionEvent event) -> {
                TreeItem selItem = tree.getSelectionModel().getSelectedItem();
                System.out.println("「" + selItem.getValue() + "」が選択されました。");
            });
            popup.getItems().add(menuItem);

            return popup;
        }
    }

    public final class TreeCellImpl extends CheckBoxTreeCell<String> {

        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);

            if (empty) {
                setText(null);
                setGraphic(null);
            } else if (getTreeItem().getClass().toString().endsWith("TreeLeaf")) {
                setContextMenu(((TreeLeaf) getTreeItem()).getMenu());
            } else {
                setText(getItem() == null ? "" : getItem());
                setGraphic(getTreeItem().getGraphic());
            }
        }
    }

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

参考サイト

  1. bitWalk's: JavaFX: TreeView と ContextMenu (2)

 

ブログランキング・にほんブログ村へ
にほんブログ村

0 件のコメント: