微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我如何将焦点侦听器放在 JavaFX 中的 Treecell 上?

如何解决我如何将焦点侦听器放在 JavaFX 中的 Treecell 上?

我正在构建一个应用程序,我需要在显示数据的窗格旁边有一个树视图。当有人在树视图中选择一个项目时,应用程序必须确定他们选择了什么并从数据库中寻找正确的数据,然后以我选择的格式呈现它。用户如何选择树视图中的项目(鼠标单击、Tab 键、箭头键等)并不重要,只要当项目获得焦点时,就会触发一个方法将数据呈现给用户

我通过以下方式为仅鼠标点击完美地工作:

    // Application thread method to build the tree map,used in the generateTree
    // method.
    public void treeBuilder(TreeMap<ModelSites,ArrayList<ModelPlants>> map) {
        
        TreeMap<ModelSites,ArrayList<ModelPlants>> treeMap = map;

        final TreeItemProperties<String,String> roottreeItem = new TreeItemProperties<String,String>("EMT",null);

        TreeItemProperties<String,Integer> site = null;
        TreeItemProperties<String,Integer> plant = null;
        
        for (Map.Entry<ModelSites,ArrayList<ModelPlants>> entry : treeMap.entrySet()) {
            site = new TreeItemProperties<String,Integer>(entry.getKey().getLongName(),entry.getKey().getPrimaryKey());
            roottreeItem.getChildren().add(site);

            if (site.getValue().equalsIgnoreCase("test item")) {
                site.setExpanded(true);
            }

            for (int i = 0; i < entry.getValue().size(); i++) {
                plant = new TreeItemProperties<String,Integer>(entry.getValue().get(i).getSitePlantId() + " " + entry.getValue().get(i).getShortName(),entry.getValue().get(i).getPrimaryKey());
                site.getChildren().add(plant);
            }
        }
        
        //Cell Factory is used to effectively turn the tree items into nodes,which they are not natively.
        //This is necessary to have actions linked to the tree items (eg. double click an item to open an edit window).
        emtTree.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>() {

            @Override
            public TreeCell<String> call(TreeView<String> param) {
                FactoryTreeCell<String> cell = new FactoryTreeCell<String>();

                cell.setonMouseClicked(event -> {
                    if (!cell.isEmpty()) {
                        @SuppressWarnings("unchecked")
                        TreeItemProperties<String,Integer> treeItem = (TreeItemProperties<String,Integer>) cell.getTreeItem();
                        generateEquipmentPanes(treeItem.getPropertyValue());
                    }
                });
                return cell;
            }
        });

        roottreeItem.setExpanded(true);
        emtTree.setRoot(roottreeItem);
    }

// Populate the main screen with all equipment items in the selected plant.
    public void generateEquipmentPanes(int plantId) {

        int plant = plantId;
        
        Task<LinkedList<ModelEquipment>> task = new Task<LinkedList<ModelEquipment>>() {
            @Override
            public LinkedList<ModelEquipment> call() {
                LinkedList<ModelEquipment> equipmentList = DAOEquipment.listEquipmentByPlant(plant);
                return equipmentList;
            }
        };

        // When list is built successfully,send the results back to the application
        // thread to load the equipment panes in the GUI.
        task.setonSucceeded(e -> equipmentPaneBuilder(task.getValue()));
        task.setonFailed(e -> task.getException().printstacktrace());
        task.setonCancelled(null);

        String methodName = new Object() {}.getClass().getEnclosingMethod().getName();

        Thread thread = new Thread(task);
        thread.setName(methodName);
        //System.out.println("Thread ID: " + thread.getId() + ",Thread Name: " + thread.getName());
        thread.setDaemon(true);
        thread.start();
    }

    // Application thread method to build the equipment panes,used in the
    // generateEquipmentPanes method.
    public void equipmentPaneBuilder(LinkedList<ModelEquipment> list) {
        LinkedList<ModelEquipment> equipmentList = list;
        
        EquipmentPanels.getChildren().clear();

        for (int i = 0; i < equipmentList.size(); i++) {
            ModelEquipment item = equipmentList.get(i);

            try {
                PaneEquipment equipmentPane = new PaneEquipment();
                equipmentPane.updateFields(item.getTechId(),item.getShortName(),item.getLongDesc()); equipmentPane.setId("equipPane" + i);
                            
                EquipmentPanels.getChildren().add(equipmentPane);
            } catch (Exception e) {
                e.printstacktrace();
            }
        }
    }

我已经进行了大量的搜索,并且想出了如何实现侦听器而不是处理程序,因为这似乎是我想做的事情的方式 - 将侦听器放在单元格的属性上。但是当用监听器替换事件处理程序时,就像下面两个例子一样,我遇到了很多问题。

                emtTree.getSelectionModel().selectedItemproperty().addListener((observable,oldValue,newValue) -> {
                    if (newValue != null) {
                        @SuppressWarnings("unchecked")
                        TreeItemProperties<String,Integer>) cell.getTreeItem();
                        generateEquipmentPanes(treeItem.getPropertyValue());
                    }
                });
                cell.focusedproperty().addListener(new changelistener<Boolean>() {

                    @Override
                    public void changed(ObservableValue<? extends Boolean> observable,Boolean oldValue,Boolean newValue) {
                        if (!cell.isEmpty()) {
                            @SuppressWarnings("unchecked")
                            TreeItemProperties<String,Integer>) cell.getTreeItem();
                            generateEquipmentPanes(treeItem.getPropertyValue());
                        }
                    }
                    
                });

首先,每次单击来自行 nullpointerexceptions 的树项时,我都会得到 generateEquipmentPanes(treeItem.getPropertyValue());。其次,它倾向于从错误的项目中选择数据,而不是我选择的项目。然后点击几下后,它似乎完全崩溃了,除了提供更多 nullpointerexceptions 之外什么都不做。

据我所知,我认为问题在于侦听器相对于需要传递给方法 generateEquipmentPanes 的变量的位置。还有一些关于在某个时间点移除监听器并稍后重新添加它们的内容

我应该以某种方式将听众放入细胞工厂吗?目前它看起来像这样:

import javafx.scene.control.TreeCell;

public class FactoryTreeCell<T> extends TreeCell<T> {
    
    public FactoryTreeCell() {
    }
    
    /*  
     * The update item method simply displays the cells in place of the tree items (which disappear when setCellFactory is set.
     * This can be used for many more things (such as customising appearance) not implemented here.
    */
    @Override
    protected void updateItem(T item,boolean empty) {
        super.updateItem(item,empty);
        
        if (empty || item == null) {
            setText(null);
            setGraphic(null);   //Note that a graphic can be many things,not just an image.  Refer openJFX website for more details.
        } else {
            setText(item.toString());
        }
    }
    
}

我注意到的另一件事是,还有其他方法可以实现 Callback,这可能对侦听器更有效,但我不知道该怎么做。

我已经坚持了很长时间,所以突破会很棒。

解决方法

您不应使用树单元格来检查所选值。您的 ChangeListener 已经直接接收到新值:

emtTree.getSelectionModel().selectedItemProperty().addListener(
    (observable,oldSelection,newSelection) -> {
        if (newSelection != null) {
            TreeItemProperties<String,Integer> treeItem = newSelection;
            generateEquipmentPanes(treeItem.getPropertyValue());
        }
    });

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。