簡體   English   中英

如何將焦點監聽器放在 JavaFX 中的 Treecell 上?

[英]How do i put a focus listener on a Treecell in JavaFX?

我正在構建一個應用程序,我需要在顯示數據的窗格旁邊有一個樹視圖。 當有人在樹視圖中選擇一個項目時,應用程序必須識別他們選擇的內容並從數據庫中尋找正確的數據,然后以我選擇的格式顯示它。 用戶如何在樹視圖中選擇項目(鼠標單擊、制表鍵、箭頭鍵等)並不重要,只要當項目獲得焦點時,就會觸發一個方法將數據呈現給用戶。

只能通過以下方式完美地使用鼠標單擊

    // 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> treeItem = (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> treeItem = (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());
        }
    });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM