【问题标题】:javaFX: radio buttons inside listview selectionmodeljavaFX:列表视图选择模型内的单选按钮
【发布时间】:2017-12-11 16:36:47
【问题描述】:

我需要在RadioButtons 里面ListView 所以我找到了这个答案:

javaFX:listview with Radio Button

但问题是ListView 中的选定单元格和选定的RadioButton 未绑定。如果单击列表中的单元格,我想自动选择相应的RadioButton

所以我的问题是如何绑定这两者?

更新: 所以我设法做到这一点的唯一方法类似于@Sedrick Jefferson 的回答,但没有在RadioButton 前面添加StackPane。 我将名单添加@ 9876543330 ToggleGroup并添加侦听器到selectedToggleProperty:选择新RadioButton ListView

中选择相应的行
    import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class RadioButtonListView extends Application
{

    public static final ObservableList<RadioButton> namesRadioButtons
            = FXCollections.observableArrayList();
    private ToggleGroup group = new ToggleGroup();

    @Override
    public void start(Stage primaryStage)
    {
        primaryStage.setTitle("List View Sample");

        final ListView<RadioButton> listView = new ListView();
        listView.setPrefSize(200, 250);
        listView.setEditable(true);

        String[] names =
        {
            "Adam", "Alex", "Alfred", "Albert",
            "Brenda", "Connie", "Derek", "Donny",
            "Lynne", "Myrtle", "Rose", "Rudolph",
            "Tony", "Trudy", "Williams", "Zach"
        };

        for (String name : names)
        {
            namesRadioButtons.add(new RadioButton(name));
        }
        group.getToggles().addAll(namesRadioButtons);
        listView.setItems(namesRadioButtons);
        group.selectedToggleProperty().addListener((obs, oldSel, newSel) -> {
            listView.getSelectionModel().select((RadioButton) newSel);
            listView.getFocusModel().focus(listView.getSelectionModel().getSelectedIndex());
        });
        listView.setCellFactory(param -> new RadioListCell());
        listView.getSelectionModel().selectedItemProperty().addListener((obs, oldSel, newSel) ->
        {
            if (newSel != null)
            {
                RadioButton tempRadioButton = (RadioButton) newSel;
                tempRadioButton.setSelected(true);
            }
            if (oldSel != null)
            {
                RadioButton tempRadioButton = (RadioButton) oldSel;
                tempRadioButton.setSelected(false);
            }
        });

        StackPane root = new StackPane();
        root.getChildren().add(listView);
        primaryStage.setScene(new Scene(root, 200, 250));
        primaryStage.show();
    }

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

    private class RadioListCell extends ListCell<RadioButton>
    {

        @Override
        public void updateItem(RadioButton obj, boolean empty)
        {
            super.updateItem(obj, empty);
            if (empty)
            {
                setText(null);
                setGraphic(null);
            }
            else
            {
                setGraphic(obj);
            }
        }

    }
}

问题:有没有更好的解决方案?

【问题讨论】:

  • 正如我已经说过的:将控件用作数据项是完全错误的 - 所以你所做的也是错误的。相反,使用具有单选按钮的自定义单元格(就像在您引用的 QA 中一样),根据需要使用文本/选定状态对其进行配置。要使列表的选择状态与按钮状态保持同步,请收听收音机在 单元格中选择的

标签: java javafx


【解决方案1】:

重复一遍:添加控件作为数据项不是解决方案!

取而代之的是,根据需要使用具有控件的自定义单元格,并使用项目/列表/选择的状态进行配置,就像在QA cited by the OP 中一样。唯一缺少的部分是反向同步(从无线电状态到列表选择):要实现这一点,请在单元中安装一个侦听器。

类似(修改示例):

public class RadioButtonListView extends Application {

    public static final ObservableList names =
            FXCollections.observableArrayList();
    private ToggleGroup group = new ToggleGroup();

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("List View Sample");

        final ListView listView = new ListView();
        listView.setPrefSize(200, 250);
        listView.setEditable(true);

        names.addAll(
                "Adam", "Alex", "Alfred", "Albert",
                "Brenda", "Connie", "Derek", "Donny",
                "Lynne", "Myrtle", "Rose", "Rudolph",
                "Tony", "Trudy", "Williams", "Zach"
        );

        listView.setItems(names);
        listView.setCellFactory(param -> new RadioListCell());

        StackPane root = new StackPane();
        root.getChildren().add(listView);
        primaryStage.setScene(new Scene(root, 200, 250));
        primaryStage.show();
    }

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

    private class RadioListCell extends ListCell<String> {

        RadioButton radioButton;
        ChangeListener<Boolean> radioListener = (src, ov, nv) -> radioChanged(nv);
        WeakChangeListener<Boolean> weakRadioListener = new WeakChangeListener(radioListener);

        public RadioListCell() {
            radioButton = new RadioButton();
            radioButton.selectedProperty().addListener(weakRadioListener);
            radioButton.setFocusTraversable(false);
            // let it span the complete width of the list
            // needed in fx8 to update selection state
            radioButton.setMaxWidth(Double.MAX_VALUE);
        }

        protected void radioChanged(boolean selected) {
            if (selected && getListView() != null && !isEmpty() && getIndex() >= 0) {
                getListView().getSelectionModel().select(getIndex());
            }
        }

        @Override
        public void updateItem(String obj, boolean empty) {
            super.updateItem(obj, empty);
            if (empty) {
                setText(null);
                setGraphic(null);
                radioButton.setToggleGroup(null);
            } else {
                radioButton.setText(obj);
                radioButton.setToggleGroup(group);
                radioButton.setSelected(isSelected());
                setGraphic(radioButton);
            }
        }
    }
}

更新:

该示例在 fx9 中运行良好,但在 fx8 中存在问题:

  • 在单选按钮外部(在一行的尾随空白处)单击时,所选单选并不总是更新。这可以通过强制收音机拉伸到列表的整个宽度来解决。

  • 当 listView 的选择改变时,收音机的选中状态并不总是更新。这可以通过在单元格的 selected 属性中安装一个侦听器并更新该侦听器中的收音机来处理。

  • 当重新使用小区时,无线电的选定状态不会可靠地更新。这需要进一步挖掘......

【讨论】:

  • 是的,但这仅在您单击单选按钮时才有效,如果您单击列表行(其中不是单选按钮),它将不会选择相应的单选按钮。还是谢谢你。
  • hmm ...无法重现您的问题:在行中的任意位置单击后选择了该项目
  • @krupiceva 您确实尝试过这个修改过的(与旧的 QA 相比)示例,不是吗? fx8 和 fx9 的工作表
  • 是的,在 fx8 中。这是我运行它时的样子:imgur.com/oggsMq7
  • 您可以为单选按钮的背景着色并张贴图片吗?对我来说它看起来像this,所以只有红色区域被注册为点击。
猜你喜欢
  • 2016-06-17
  • 2018-09-19
  • 2014-06-19
  • 2013-04-12
  • 2014-07-31
  • 2015-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多