带有 RadioButtons 的 JavaFX TreeView 在滚动时显示不正确的状态
JavaFX TreeView with RadioButtons displaying incorrect status when scrolling
我需要一个 TreeView
,其中一些元素有 RadioButton
。
所以我环顾四周,使用了 here 中的一些代码,并将我自己的一些想法放在那里。
所以结果是 class (RadioTreeView
) 扩展 TreeView
自定义 TreeItem
s 和 TreeCell
s.
一切正常,除了一件重要的事情:
滚动 TreeView
并选中一个 RadioButton
时,其他按钮将显示为已选中。
这个 gif 演示了这个问题。(我在滚动时没有点击任何地方)
通过一些调试,我发现 ToggleGroup
的 selectedItem-属性(由所有 RadioButton
s 在 TreeView
) 中,实际上永远不会改变。
当我为每个 RadioButton
s' selected-属性 添加一个监听器时,它们也从未触发。
所以这让我感到困惑和疑惑,这是一个 JavaFX 错误还是我遗漏了一些非常明显的东西。
这是我的代码:
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.util.Callback;
public class RadioTreeView<T> extends TreeView<T> {
private ToggleGroup toggleGroup; // shared by all radioButtons
public RadioTreeView() {
super();
toggleGroup = new ToggleGroup();
setCellFactory(new Callback<TreeView<T>, TreeCell<T>>() {
@Override
public TreeCell<T> call(TreeView<T> param) {
return new RadioTreeCell<T>(toggleGroup);
}
});
}
public static class RadioTreeItem<T> extends TreeItem<T> {
private final boolean hasRadio; // defines whether a RadioButton should be shown
public RadioTreeItem(boolean hasRadio, T item) {
super(item);
this.hasRadio = hasRadio;
}
public boolean getHasRadio() {
return hasRadio;
}
}
public static class RadioTreeCell<T> extends TreeCell<T> {
private final RadioTreeButton<T> radio = new RadioTreeButton<T>();
private final ToggleGroup toggleGroup;
public RadioTreeCell(ToggleGroup toggleGroup) {
super();
this.toggleGroup = toggleGroup;
}
{
setContentDisplay(ContentDisplay.LEFT);
}
@Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
setText(item.toString());
if (((RadioTreeItem<T>) getTreeItem()).getHasRadio()) { // display radioButton as graphic
setGraphic(radio);
radio.setToggleGroup(toggleGroup);
} else {
setGraphic(null);
}
} else {
setGraphic(null);
setText(null);
}
}
}
private static class RadioTreeButton<T> extends RadioButton {
// non-important methods removed
public RadioTreeButton() {
}
}
非常感谢任何帮助。
PS:我知道我的代码并不完美
TreeCell
被重用。这意味着可以在包含不同 TreeItem
的单元格中使用单个 RadioButton
。您永远不会根据项目更新单元格中 RadioButton
的选择状态。这导致相同的 RadioButton
保持选中状态。滚动时,不同的 TreeItem
会被放入不同的单元格中。 TableCell
的文本已更新,但其 RadioButton
的选择状态未更新。
您需要以某种方式存储所选 TreeItem
,例如使用 userData
属性 的 ToggleGroup
:
public RadioTreeCell(ToggleGroup toggleGroup) {
this.toggleGroup = toggleGroup;
setContentDisplay(ContentDisplay.LEFT); // initializer code moved to constructor
// update userData for toggleGroup, when new radio becomes selected
radio.selectedProperty().addListener((o, oldValue, newValue) -> {
if (newValue) {
toggleGroup.setUserData(getTreeItem());
}
});
}
@Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
setText(item.toString());
RadioTreeItem<T> treeItem = (RadioTreeItem<T>) getTreeItem();
if (treeItem.getHasRadio()) { // display radioButton as graphic
setGraphic(radio);
radio.setToggleGroup(toggleGroup);
// update selection based on toggleGroup userData
radio.setSelected(toggleGroup.getUserData() == treeItem);
} else {
setGraphic(null);
}
} else {
setGraphic(null);
setText(null);
}
}
我需要一个 TreeView
,其中一些元素有 RadioButton
。
所以我环顾四周,使用了 here 中的一些代码,并将我自己的一些想法放在那里。
所以结果是 class (RadioTreeView
) 扩展 TreeView
自定义 TreeItem
s 和 TreeCell
s.
一切正常,除了一件重要的事情:
滚动 TreeView
并选中一个 RadioButton
时,其他按钮将显示为已选中。
这个 gif 演示了这个问题。(我在滚动时没有点击任何地方)
通过一些调试,我发现 ToggleGroup
的 selectedItem-属性(由所有 RadioButton
s 在 TreeView
) 中,实际上永远不会改变。
当我为每个 RadioButton
s' selected-属性 添加一个监听器时,它们也从未触发。
所以这让我感到困惑和疑惑,这是一个 JavaFX 错误还是我遗漏了一些非常明显的东西。
这是我的代码:
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.util.Callback;
public class RadioTreeView<T> extends TreeView<T> {
private ToggleGroup toggleGroup; // shared by all radioButtons
public RadioTreeView() {
super();
toggleGroup = new ToggleGroup();
setCellFactory(new Callback<TreeView<T>, TreeCell<T>>() {
@Override
public TreeCell<T> call(TreeView<T> param) {
return new RadioTreeCell<T>(toggleGroup);
}
});
}
public static class RadioTreeItem<T> extends TreeItem<T> {
private final boolean hasRadio; // defines whether a RadioButton should be shown
public RadioTreeItem(boolean hasRadio, T item) {
super(item);
this.hasRadio = hasRadio;
}
public boolean getHasRadio() {
return hasRadio;
}
}
public static class RadioTreeCell<T> extends TreeCell<T> {
private final RadioTreeButton<T> radio = new RadioTreeButton<T>();
private final ToggleGroup toggleGroup;
public RadioTreeCell(ToggleGroup toggleGroup) {
super();
this.toggleGroup = toggleGroup;
}
{
setContentDisplay(ContentDisplay.LEFT);
}
@Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
setText(item.toString());
if (((RadioTreeItem<T>) getTreeItem()).getHasRadio()) { // display radioButton as graphic
setGraphic(radio);
radio.setToggleGroup(toggleGroup);
} else {
setGraphic(null);
}
} else {
setGraphic(null);
setText(null);
}
}
}
private static class RadioTreeButton<T> extends RadioButton {
// non-important methods removed
public RadioTreeButton() {
}
}
非常感谢任何帮助。
PS:我知道我的代码并不完美
TreeCell
被重用。这意味着可以在包含不同 TreeItem
的单元格中使用单个 RadioButton
。您永远不会根据项目更新单元格中 RadioButton
的选择状态。这导致相同的 RadioButton
保持选中状态。滚动时,不同的 TreeItem
会被放入不同的单元格中。 TableCell
的文本已更新,但其 RadioButton
的选择状态未更新。
您需要以某种方式存储所选 TreeItem
,例如使用 userData
属性 的 ToggleGroup
:
public RadioTreeCell(ToggleGroup toggleGroup) {
this.toggleGroup = toggleGroup;
setContentDisplay(ContentDisplay.LEFT); // initializer code moved to constructor
// update userData for toggleGroup, when new radio becomes selected
radio.selectedProperty().addListener((o, oldValue, newValue) -> {
if (newValue) {
toggleGroup.setUserData(getTreeItem());
}
});
}
@Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
setText(item.toString());
RadioTreeItem<T> treeItem = (RadioTreeItem<T>) getTreeItem();
if (treeItem.getHasRadio()) { // display radioButton as graphic
setGraphic(radio);
radio.setToggleGroup(toggleGroup);
// update selection based on toggleGroup userData
radio.setSelected(toggleGroup.getUserData() == treeItem);
} else {
setGraphic(null);
}
} else {
setGraphic(null);
setText(null);
}
}