JavaFX ComboBox:从ListView

时间:2016-01-06 22:21:26

标签: javafx javafx-8

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

问题:

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

详细问题描述:

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

的尝试:

  1. 我尝试的第一个解决方案是在组合框valueProperty上添加更改侦听器(这是弹出窗口关闭时在文本字段中显示的值)。因此,当用户单击监听时,弹出窗口关闭,单击的条目将放入值字段,更改值,从而触发我的更改侦听器。这适用于鼠标,但是键盘导航无法正常工作,因为每次用户在列表中向下或向上导航时,组合框的值字段都会使用当前选定的listentry进行更新,因此每次都会触发我的changelistener(反过来)将值添加到我的其他列表中,而只应在输入keypress上添加。
  2. 下一个解决方案是不向valueProperty添加监听器,而是向showingProperty添加监听器。每次组合框弹出窗口关闭时,都会获取值字段的当前值并将其添加到另一个列表中。这对鼠标再次有效,但仍然存在键盘导航问题。虽然它现在正确处理列表中的向上/向下导航并输入按键,但现在问题是当您尝试取消选择时。当您按下escape时,也会获取该值并将其添加到另一个列表中,就像您按下Enter键一样。这种方法的问题在于我无法找到弹出窗口已关闭的按键。
  3. 所以下一个想法是使用ComboBox的addEventFilter方法向组合框本身添加一个事件过滤器,其代码类似于以下(此处也提出StackOverflow):

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

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

2 个答案:

答案 0 :(得分:0)

在寻找其他问题时,请问这个问题。它涉及到我之前所做的事情,因此假设我理解您要完成的工作,并且在此处仍然有意义,这里有一些想法。

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

  1. 组合框的ChangeListener的{​​{1}}属性上的selectedItem。单击弹出式(下拉)列表视图中的项目将更改selectionModel 并关闭“拥有”列表视图的selectedItem,或者
  2. 用于事件类型Window的组合框的事件处理程序,该事件处理程序在列表视图关闭时触发(或者最好说“变成隐藏”)。

ComboBoxBase.ON_HIDDEN可能有问题,因为组合框和列表视图的选择模型处于较低级别,因此列表视图的ChangeListener值更改为使用击键进行导航时触发的触发必须由selectedItem处理。因为您只想在按ENTER键时同步组合框和列表#2,所以这可能无法工作。但这仍然使事件处理程序的想法可以尝试。

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

希望这会有所帮助。

答案 1 :(得分:0)

以下代码的想法是,一旦将组合框加载到JavaFX场景中,便创建了ListView。因此,我们在组合框上添加了一个侦听器以检查它何时出现在场景中,然后通过“ lookup”方法获得其列表视图并向其添加侦听器。

在该示例中,我设置了一个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