【问题标题】:JavaFX ComboBox: Receive mouseclick/keypress events from ListViewJavaFX ComboBox:从 ​​ListView 接收鼠标单击/按键事件
【发布时间】:2016-01-06 22:21:25
【问题描述】:

我从问题开始,然后更详细地描述问题:

问题:

有没有办法直接从 JavaFx ComboBox 的列表视图接收事件(据我所知,ComboBox 由列表视图和文本字段组成)?我想找出列表中的哪个元素已被鼠标单击,或者当用户在键盘上按下 enter 时选择了哪个元素(在列表中使用向上/向下箭头导航之后)。因此,我需要在列表视图上接收鼠标单击事件或按键事件,但到目前为止,我所能得到的只是组合框本身上的事件,结果只是组合框文本字段中的更改。

详细问题描述:

我有一个带有组合框的 JavaFx 应用程序,其想法是当用户单击组合框列表中的条目时(当组合框的弹出窗口打开时),该值会直接添加到另一个列表中。此外,当用户使用键盘上的箭头键在组合框列表中导航并按下回车键时,应采用当前选择的值并将其添加到另一个列表中。但是到目前为止,我还没有发现如何使用标准的 JavaFx 组合框来实现此功能。

试过了:

  1. 我尝试的第一个解决方案是在组合框的valueProperty 上添加一个更改侦听器(这是关闭弹出窗口时在文本字段中显示的值)。因此,当用户单击列表条目时,弹出窗口关闭并将单击的条目放入值字段中,更改值并因此触发我的更改侦听器。这适用于鼠标,但键盘导航无法正常工作,因为每次用户在列表中向下或向上导航时,组合框的 value 字段都会使用当前选择的 listentry 更新,因此每次都会触发我的 changelistener(反过来将该值添加到我的其他列表中,而它应该只在输入键时添加)。
  2. 下一个解决方案是不向valueProperty 添加侦听器,而是向showingProperty 添加侦听器。每次组合框弹出窗口关闭时,都会获取 value 字段的当前值并将其添加到另一个列表中。这同样适用于鼠标,但仍然存在键盘导航问题。虽然它现在可以正确处理列表中的向上/向下导航并输入按键,但现在问题出在您尝试取消选择时。当您按下 Escape 时,该值也会被获取并添加到另一个列表中,就像您按下 Enter 键一样。这种方法的问题是我无法确定弹出窗口是通过哪个按键关闭的。

所以我的下一个想法是使用 ComboBox 的 addEventFilter 方法向组合框本身添加一个事件过滤器,其代码类似于以下(这里也建议 StackOverflow):

ComboBox comboBox = new ComboBox();
comboBox.addEventFilter(KeyEvent.KEY_PRESSED, (event) -> {
    // do stuff
});

但是当组合框弹出窗口打开时,事件过滤器永远不会被调用。它仅在弹出窗口关闭时调用,这导致我假设事件被列表视图消耗。因此,问题的唯一解决方案似乎是以某种方式从列表视图本身捕获事件。这又回到了本文开头的问题。抱歉解释太长了。:-)

【问题讨论】:

  • 嗯...也许提供一个cellFactory 并向每个ComboBoxListCellselected 属性添加一个侦听器?不确定它是否会起作用,但也许值得一试。
  • 有趣的问题。我找不到办法做到这一点。最重要的是,在您关闭弹出窗口之前,组合框实际上会在您使用键导航时设置值。 (我想这只是观察列表视图的选定项属性。)您对showingProperty 的想法确实是正确的,请注意,转义键的问题基本上只是由于转义键没有似乎没有在任何意义上取消选择。 (如果您打开组合框,用键导航,然后按 Escape,键选择的最后一项将显示在组合框中。)
  • 你能用ChoiceBox代替ComboBox吗?
  • @sillyfly:好主意。但最后,我仍然需要知道用户是否取消了输入(使用 selected 属性我只知道最后选择的项目)。
  • @James_D:ChoiceBox 并不是我所需要的(应该可以不选择任何值并改为显示“选择值...”)。但也许可以对其进行调整以使其像这样工作。我考虑了一下。

标签: javafx javafx-8


【解决方案1】:

在寻找其他东西时遇到了这个问题。它涉及到我之前做过的一些事情,所以假设我理解你想要完成的事情,并且这仍然是相关的,这里有几个想法。

要使其他列表(列表#2)与鼠标点击的组合框保持同步,请尝试:

  1. 组合框selectionModelselectedItem 属性上的ChangeListener。单击弹出(下拉)列表视图中的项目将更改 selectedItem关闭“拥有”列表视图的 Window,或
  2. 事件类型ComboBoxBase.ON_HIDDEN 的组合框的事件处理程序,当列表视图关闭(或者更好地称为“隐藏”)时触发。

ChangeListener 可能存在问题,因为组合框和列表视图的选择模型在低级别链接,因此列表视图的 selectedItem 值的更改将在导航时触发击键必须由ChangeListener 处理。由于您只想在按下 ENTER 键时同步组合框和列表 #2,因此这可能不起作用。但这仍然让事件处理程序的想法有待尝试。

对于 ENTER 按键,您需要获取列表视图本身的句柄,然后根据需要添加任何行为(侦听器/事件处理程序)。为此,您可以获取组合框的皮肤,它应该是ComboBoxListViewSkin 的一个实例,然后通过调用皮肤的getPopupContent() 方法来获取列表视图;它以Node 的形式返回弹出列表视图,因此您可以重铸返回的值,但没什么大不了的。

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    以下代码的想法是,一旦组合框在 JavaFX 场景中加载,就会创建 ListView。因此,我们在combobox上添加一个监听器来检查它何时出现在场景中,然后通过“lookup”方法获取它的listview并为其添加一个监听器。

    在示例中,我设置了一个 MouseEvent 侦听器,但您也可以轻松调整它的按键。

    private EventHandler<MouseEvent> cboxMouseEventHandler;
    
    private void initComboBox() {
        ComboBox<String> comboBox = new ComboBox<String>();
        comboBox.getItems().add("Item 1");
        comboBox.getItems().add("Item 2");
        comboBox.getItems().add("Item 3");
    
        comboBox.sceneProperty().addListener((a,oldScene,newScene) -> {
            if(newScene == null || cboxMouseEventHandler != null)
                return;
                
            ListView<?> listView = (ListView<?>) comboBox.lookup(".list-view");
            if(listView != null) {
                cboxMouseEventHandler = (e) -> {
                    Platform.runLater(()-> {
                        String selectedValue = (String) listView.getSelectionModel().getSelectedItem();
                        if(selectedValue.equals("Item 1"))
                            System.out.println("Item 1 clicked");
                    });
                }; // cboxMouseEventHandler
            
                listView.addEventFilter(MouseEvent.MOUSE_PRESSED, cboxMouseEventHandler); 
            } // if
        });
    } // initComboBox
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多