点击

时间:2015-08-13 11:42:03

标签: listview javafx-8

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

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处理程序时会发生这种情况。鼠标单击不执行任何操作。

2 个答案:

答案 0 :(得分:3)

你不应该用updateItem()方法设置监听器,因为在渲染列表单元格时会多次调用它,你不想再次不必要地设置它们。此外,在updateItem() item的某些情况下,getItem()将为空,即单元格将为空,因此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; } } ); 将返回null。

尝试

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 ); } });

function test(val) {
    var x = Math.floor(val);
    return (val - x) > 0.5 ? Math.ceil(val) : (x + 0.5);
}

答案 1 :(得分:2)

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

  1. 必须致电super.updateItem(...)。这是为了正确维护itemempty属性的状态,以及处理诸如为选择和焦点设置CSS伪类状态等事项所必需的
  2. 您必须处理单元格为空(或项目为空)的情况,并在这种情况下清除文本。
  3. 此外,正如Uluk Biy的回答所指出的那样,在updateItem(...)方法中设置处理程序并不是一个好主意。经常调用此方法,并且只需在创建单元格时设置一次处理程序。

    所以你的细胞工厂看起来应该是

    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 ;
    }