[英]How do i put a focus listener on a Treecell in JavaFX?
I am building am application where I need to have a tree view alongside a pane where data is presented.我正在构建一个应用程序,我需要在显示数据的窗格旁边有一个树视图。 When someone selects an item in the tree view, the application must identify what they have selected and seek the correct data from a database, then present it in the format I've chosen.
当有人在树视图中选择一个项目时,应用程序必须识别他们选择的内容并从数据库中寻找正确的数据,然后以我选择的格式显示它。 It must not matter how the user selects the item in the tree view (mouse click, tabbing, arrow keys, etc), just that when an item gets focus, a method is triggered to present the data to the user.
用户如何在树视图中选择项目(鼠标单击、制表键、箭头键等)并不重要,只要当项目获得焦点时,就会触发一个方法将数据呈现给用户。
I got this working perfectly for mouse clicks only in the following way:我只能通过以下方式完美地使用鼠标单击:
// 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();
}
}
}
I've done a tonne of searching and I sort of figured out how to implement listeners instead of handlers as this seemed to be the way to do what I want - put a listener on a property of the cell.我已经进行了大量的搜索,我有点想出如何实现侦听器而不是处理程序,因为这似乎是做我想做的事情的方式 - 将侦听器放在单元格的属性上。 But when replace the event handler with the listener, like the below two examples, I get many issues.
但是当用监听器替换事件处理程序时,就像下面的两个例子一样,我遇到了很多问题。
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());
}
}
});
For a start I get nullpointerexceptions
every time I click on a tree item, which comes from the line generateEquipmentPanes(treeItem.getPropertyValue());
首先,每次单击树项时都会收到
nullpointerexceptions
,该树项来自行generateEquipmentPanes(treeItem.getPropertyValue());
. . Secondly, it tends to pick data from the wrong item, not the one I selected.
其次,它倾向于从错误的项目中选择数据,而不是我选择的项目。 Then after a few clicks it seems to break down altogether and do nothing except provide more
nullpointerexceptions
.然后单击几下后,它似乎完全崩溃了,除了提供更多
nullpointerexceptions
之外什么也不做。
From what I can understand, I think that the issue is the location of the listener relative to the variables that need to be passed to the method generateEquipmentPanes
.据我了解,我认为问题在于侦听器相对于需要传递给方法
generateEquipmentPanes
的变量的位置。 And something about removing listeners at a certain point and re-adding them later.还有一些关于在某个时间点移除监听器并稍后重新添加它们的东西。
Should I somehow be putting the listener into the cell factory?我应该以某种方式将听众放入细胞工厂吗? At the moment it just looks like this:
目前它看起来像这样:
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());
}
}
}
Another thing I've noticed is that there are other ways to implement the Callback
, that might work better with listeners, but I don't know how to do that.我注意到的另一件事是,还有其他方法可以实现
Callback
,这可能对侦听器更有效,但我不知道该怎么做。
I've been stuck on this for ages so a breakthrough would be great.我多年来一直坚持这一点,所以突破会很棒。
You should not be using a tree cell to examine the selected value.您不应该使用树单元格来检查所选值。 Your ChangeListener already receives the new value directly:
您的 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.