【问题标题】:Get object from ListView's ListItem on click单击时从 ListView 的 ListItem 中获取对象
【发布时间】:2015-08-13 11:42:03
【问题描述】:

我有一个填充了可观察列表的列表视图

availableSymbolsTable.setItems(watch.GetAvailableSymbols());

细胞工厂:

availableSymbolsTable.setCellFactory(new Callback<ListView<Symbol>, ListCell<Symbol>>()
        {

            @Override
            public ListCell<Symbol> call(ListView<Symbol> p)
            {
                final ListCell<Symbol> cell = new ListCell<Symbol>()
                {
                    @Override
                    protected void updateItem(Symbol t, boolean bln)
                    {
                        if (t != null)
                        {
                            setText(t.getSymbolName());
                        }

                        setOnMouseEntered(new EventHandler<MouseEvent>()
                        {
                            @Override
                            public void handle(MouseEvent event)
                            {
                                //This works
                                System.out.println("index: " + getIndex());
                            }
                        });

                        setOnMouseClicked(new EventHandler<MouseEvent>()
                        {
                            @Override
                            public void handle(MouseEvent event)
                            {
                                 //HERE getItem() always returns null
                                System.out.println( getItem().getSymbolName());         
                            }
                        });
                    }

                };
                return cell;}});}

在 MouseClicked 事件处理程序中,getItem() 方法始终返回 null。如何获取关联的 Symbol 对象?

编辑: 如果有帮助:我不知道预期的行为,但是单击时,元素不会被选中。当我注释掉 mouseClicked 和 mouseEntered 处理程序时,会发生这种情况。鼠标点击什么都不做。

【问题讨论】:

  • 请教育我 - 为什么不赞成?
  • 选择问题是因为您忘记拨打super.updateItem(t, bln);。这必须是您的 updateItem(...) 方法的第一行。
  • @James_D 这解决了选择和我原来的问题。您应该将其发布为答案。谢谢。
  • @UlukBiy 是正确的:您不应该重复更新 updateItem(...) 方法中的处理程序。
  • @James_D 我也考虑了他的回答。结合您的两个答案,列表视图的行为符合我的预期 - 在点击事件中更改选择和获取项目。

标签: listview javafx-8


【解决方案1】:

您在 updateItem(...) 方法中省略了两件重要的事情:

  1. 必须致电super.updateItem(...)。这是为了正确维护 itemempty 属性的状态,以及处理诸如设置 CSS 伪类状态以进行选择和焦点等操作
  2. 必须处理单元格为空(或项为空)的情况,并在这种情况下清除文本。

此外,正如 Uluk Biy 的回答中所指出的,在 updateItem(...) 方法中设置处理程序并不是一个好主意。该方法被频繁调用,handlers只需要在cell创建时设置一次。

所以你的细胞工厂应该是这样的

availableSymbolsTable.setCellFactory( new Callback<ListView<Symbol>, ListCell<Symbol>>()
{
    @Override
    public ListCell<Symbol> call( ListView<Symbol> p )
    {
        final ListCell<Symbol> cell = new ListCell<Symbol>()
        {
            @Override
            protected void updateItem( Symbol t, boolean empty )
            {
                super.updateItem(t, empty);
                if (empty) {
                    setText(null);
                } else {
                    setText( t.getSymbolName() );
                }
            }
        };

        cell.setOnMouseEntered( new EventHandler<MouseEvent>()
        {
            @Override
            public void handle( MouseEvent event )
            {
                System.out.println( "index: " + cell.getIndex() );
            }
        } );

        cell.setOnMouseClicked( new EventHandler<MouseEvent>()
        {
            @Override
            public void handle( MouseEvent event )
            {
                if ( cell.getItem() != null )
                {
                    System.out.println( cell.getItem().getSymbolName() );
                }
            }
        } );

        return cell;
    }
} );

顺便说一句,由于您使用的是 JavaFX 8,因此您可以使用 Lambda 表达式大大简化此代码:

availableSymbolsTable.setCellFactory(lv -> {
    ListCell<Symbol> cell = new ListCell<Symbol>() {
        @Override
        protected void updateItem(Symbol t, boolean empty) {
            super.updateItem(t, empty);
            if (empty) {
                setText(null);
            } else {
                setText(t.getSymbolName());
            }
        }
    };

    cell.setOnMouseEntered(e -> {
        System.out.println("Index: "+cell.getIndex());
    });

    cell.setOnMouseClicked(e -> {
        if (cell.getItem() != null) {
            System.out.println(cell.getItem().getSymbolName());
        }
    });

    return cell ;
}

【讨论】:

    【解决方案2】:

    您不应该在updateItem() 方法中设置侦听器,因为在渲染列表单元格时它会被多次调用,您不想再次不必要地设置它们。此外,在 updateItem() 的某些情况下,item 将为 null,即单元格将为空,因此 getItem() 将返回 null。

    试试

    availableSymbolsTable.setCellFactory( new Callback<ListView<Symbol>, ListCell<Symbol>>()
    {
        @Override
        public ListCell<Symbol> call( ListView<Symbol> p )
        {
            final ListCell<Symbol> cell = new ListCell<Symbol>()
            {
                @Override
                protected void updateItem( Symbol t, boolean bln )
                {
                    super.updateItem(t, empty);
    
                    if ( t != null )
                    {
                        setText( t.getSymbolName() );
                    }
                    else
                    {
                        setText( null );
                    }
                }
            };
    
            cell.setOnMouseEntered( new EventHandler<MouseEvent>()
            {
                @Override
                public void handle( MouseEvent event )
                {
                    System.out.println( "index: " + cell.getIndex() );
                }
            } );
    
            cell.setOnMouseClicked( new EventHandler<MouseEvent>()
            {
                @Override
                public void handle( MouseEvent event )
                {
                    if ( cell.getItem() != null )
                    {
                        System.out.println( cell.getItem().getSymbolName() );
                    }
                }
            } );
    
            return cell;
        }
    } );
    

    还要注意,用户可以用键盘选择列表项,如果你也想处理它们,观察selectedItemProperty更合适:

    availableSymbolsTable.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Symbol>()
    {
        @Override
        public void changed( ObservableValue<? extends Symbol> observable, Symbol oldValue, Symbol newValue )
        {
            System.out.println( "newValue = " + newValue );
        }
    });
    

    【讨论】:

    • 使用您的代码(在 onMOuseClicked 中添加额外的 (Symbol)cell.getItem())代码永远不会进入 if 语句,因为 cell.getItem() 始终为 false。
    • 我会尝试使用 selectedItemProperty。在这种情况下我应该如何处理双击。假设我想在双击并输入密钥时采取相同的操作(选择项目时)。顺便说一句,感谢您到目前为止所做的努力。
    • 再一次...您必须调用super.updateItem(...),否则item 属性实际上不会正确设置。
    • 谢谢@James_D。我完全错过了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-08
    • 2015-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多