26

我有我的 JavaFX 2.0 应用程序,在用户单击 ListView 元素中的项目后,我需要在其中执行一些操作。为了构建用户 GUI,我使用了 FXML,其中我有这样的东西:

        <children>
            <ListView fx:id="listView" GridPane.columnIndex="0" 
            GridPane.rowIndex="1" labelFor="$pane" 
            onPropertyChange="#handleListViewAction"/>
        </children>

这是我在此事件的控制器中所拥有的:

        @FXML protected void handleListViewAction(ActionEvent event) {
           System.out.println("OK");
        }

当构建此 gui 的场景时,我收到一个错误:

javafx.fxml.LoadException: java.lang.String does not define a property model for "property".
at javafx.fxml.FXMLLoader$Element.processEventHandlerAttributes(Unknown Source)
at javafx.fxml.FXMLLoader$ValueElement.processEndElement(Unknown Source)
at javafx.fxml.FXMLLoader.processEndElement(Unknown Source)
at javafx.fxml.FXMLLoader.load(Unknown Source)
at javafx.fxml.FXMLLoader.load(Unknown Source)
at javafx.fxml.FXMLLoader.load(Unknown Source)
at fxmlexample.FXMLExampleController.handleSubmitButtonAction(FXMLExampleController.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Node.fireEvent(Unknown Source)
at javafx.scene.control.Button.fire(Unknown Source)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(Unknown Source)
at com.sun.javafx.scene.control.skin.SkinBase$5.handle(Unknown Source)
at com.sun.javafx.scene.control.skin.SkinBase$5.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Scene$MouseHandler.process(Unknown Source)
at javafx.scene.Scene$MouseHandler.process(Unknown Source)
at javafx.scene.Scene$MouseHandler.access$1300(Unknown Source)
at javafx.scene.Scene.impl_processMouseEvent(Unknown Source)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.notifyMouse(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(Unknown Source)
at com.sun.glass.ui.win.WinApplication$2$1.run(Unknown Source)
at java.lang.Thread.run(Thread.java:722) java.lang.NullPointerException
at javafx.scene.Scene.doCSSPass(Unknown Source)
at javafx.scene.Scene.access$2900(Unknown Source)
at javafx.scene.Scene$ScenePulseListener.pulse(Unknown Source)
at com.sun.javafx.tk.Toolkit.firePulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit$8.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(Unknown Source)
at com.sun.glass.ui.win.WinApplication$2$1.run(Unknown Source)
at java.lang.Thread.run(Thread.java:722)

并且这个异常的最后一个块(来自这里的 java.lang.NullPointerException)是循环的。

4

5 回答 5

51

FXML 属性和值直接映射到 FX API。因此,要了解如何编写处理程序,您可以首先通过 API 创建所需的实体。

似乎您想在单击鼠标时对 ListView 元素添加操作,因此您需要添加鼠标单击处理程序。在 API 中,它看起来是下一个方式:

    final ListView lv = new ListView(FXCollections.observableList(Arrays.asList("one", "2", "3")));
    lv.setOnMouseClicked(new EventHandler<MouseEvent>() {

        @Override
        public void handle(MouseEvent event) {
            System.out.println("clicked on " + lv.getSelectionModel().getSelectedItem());
        }
    });

查看该代码,您可以找出 FXML 中需要覆盖的属性onMouseClicked

<ListView fx:id="listView" onMouseClicked="#handleMouseClick"/>

在控制器中,您需要为处理程序提供MouseEvent参数:

@FXML
private ListView listView;

@FXML public void handleMouseClick(MouseEvent arg0) {
    System.out.println("clicked on " + listView.getSelectionModel().getSelectedItem());
}
于 2012-03-15T18:58:59.240 回答
9

@Sergey Grinev 的回答可能有问题。如果您的 ListView 填充不够满,换句话说可能有一些空白空间。然后你点击空白将不会触发选择更改。 在此处输入图像描述

解决方案:使用自定义 ListCell。

  1. 定义一个自定义类扩展 ListCell。
  2. 在 updateItem 函数中,您可以将项目单击事件处理程序设置为单元根节点。

如果你不知道你有多少物品。你永远不会这样做。你应该用时间换空间。

演示:

在 ListView 代码段中:

listView.setCellFactory(new AppListCellFactory());

AppListCellFactory.java:

公共类 AppListCellFactory 实现回调,ListCell> {

// only one global event handler private EventHandler<MouseEvent> oneClickHandler; public AppListCellFactory(){ oneClickHandler = new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { Parent p = (Parent) event.getSource(); // do what you want to do with data. AppClickHandler.onAppBeanClicked((AppBean) p.getUserData()); } }; } @Override public ListCell<AppBean> call(ListView<AppBean> param) { return new DemoListCell(oneClickHandler); } public static final class DemoListCell extends ListCell<AppBean> { private EventHandler<MouseEvent> clickHandler; /** * This is ListView item root node. */ private Parent itemRoot; private Label label_AppName; private ImageView imgv_AppIcon; DemoListCell(EventHandler<MouseEvent> clickHandler) { this.clickHandler = clickHandler; } @Override protected void updateItem(AppBean app, boolean empty) { super.updateItem(app, empty); if (app == null) { setText(null); setGraphic(null); return; } if (null == itemRoot) { try { itemRoot = FXMLLoader.load(getClass().getResource(("fxml/appList_item.fxml"))); } catch (IOException e) { throw new RuntimeException(e); } label_AppName = (Label) itemRoot.lookup("#item_Label_AppName"); imgv_AppIcon = (ImageView) itemRoot.lookup("#item_ImageView_AppIcon"); itemRoot.setOnMouseClicked(clickHandler); } // set user data. like android's setTag(Object). itemRoot.setUserData(app); label_AppName.setText(app.name); imgv_AppIcon.setImage(new Image(getClass().getResource("img/icon_64.png").toExternalForm())); setGraphic(itemRoot); } }

}

于 2014-04-17T06:47:36.367 回答
5

您还可以在空白处使用不需要的事件。

call()细胞工厂添加:

cell.setOnMousePressed((MouseEvent event) -> {
    if (cell.isEmpty()) {
       event.consume();
    }
});

这也会禁用click& dragStart

我项目中的整个 cellFactory 示例:

public static Callback<ListView<BlockFactory>, ListCell<BlockFactory>> getCellFactory() {
    return new Callback<ListView<BlockFactory>, ListCell<BlockFactory>>() {

        @Override
        public ListCell<BlockFactory> call(ListView<BlockFactory> param) {
            ListCell<BlockFactory> cell = new ListCell<BlockFactory>() {

                @Override
                protected void updateItem(BlockFactory item, boolean empty) {
                    super.updateItem(item, empty);
                    if (item != null) {
                        ImageView img = new ImageView(item.img);
                        Label label = new Label(item.desc);
                        HBox bar = new HBox(img, label);
                        bar.setSpacing(15);
                        bar.setAlignment(Pos.CENTER_LEFT);
                        setGraphic(bar);
                    }
                }
            };
            cell.setOnMousePressed((MouseEvent event) -> {
                if (cell.isEmpty()) {
                    event.consume();
                }
            });
            return cell;
        }
    };
}
于 2014-11-03T22:24:49.987 回答
2

对 Sergey 的回答的简单修复,无需创建一个全新的 listCell (在您的情况下,您可以这样做,但我们不必在常规文本情况下创建)。

您需要做的只是首先创建一个等于第一个列表项的临时变量,然后将其更改为每个新的单击项。一旦您尝试再次单击该项目,临时变量就会知道它是相同的,并且使用 if 语句可以解决这个问题。

temp Item 是您放置在顶部的全局变量 String tempItem = "admin";

对我来说,我知道我的第一个字段总是会被标记为“管理员”,所以我将其设置为这样。您必须获取第一个条目并将其设置在您将用于列表选择的方法之外。

private void selUser() throws IOException
    {
    String item = userList.getSelectionModel().getSelectedItem().toString();

        if(item != tempItem)
        {
           //click, do something
        }

        tempItem = item;    
}

至于我,我使用了一个调用我的方法的 FXML 文档

@FXML 
public void userSel(MouseEvent mouse) throws IOException
{
selUser();

}

在这种情况下,您可以只获取 selUser() 方法的全部内容并将其放入 userSel 鼠标单击中。

于 2014-09-28T18:27:56.083 回答
0

获取旧位置索引(在列表视图中搜索结果之后)、新位置索引、值等:

listView.setOnMouseClicked(me -> {
    System.out.println("clicked on " + listView.getSelectionModel().getSelectedItem());

    int newPosition = listView.getSelectionModel().getSelectedIndex();
    System.out.println("New Position is: " + newPosition);

    String item = listView.getSelectionModel().getSelectedItem();
    int oldPosition = observableMainList.indexOf(item); // the main list which populated the listView 
    System.out.println("Old position is: " + oldPosition);

    String ayahRanges = ayahNumbers.get(oldPosition); // another list which you store some another value 
    System.out.println("Actual AyaRanges: " + ayahRanges);
});
于 2021-09-05T16:33:17.537 回答