自定义Java-fx cellfactory混淆了setCellValueFactory [英] Custom Java-fx cellfactory messes up the setCellValueFactory

查看:281
本文介绍了自定义Java-fx cellfactory混淆了setCellValueFactory的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在搞乱Netbeans和Scenebuilder一段时间后,我遇到了一个我无法理解的问题。我使用自定义 cellfactory 将doubleclick事件绑定到tableview中的单元格。但是当我设置cellfactory 一个cellValueFactory时,只有自定义的cellFactory有效。

After messing around with Netbeans and Scenebuilder for a while I'm stuck at a problem I can't quite understand. I use a custom cellfactory to bind a doubleclick event to the cells in my tableview. But when I set the cellfactory and a cellValueFactory only the custom cellFactory has an effect.

我正在尝试使用来自的数据填充tableview许多对象并将双击事件绑定到第一列的单元格。填充不是问题,我刚刚使用

I'm trying to populate a tableview with data from a number of objects and bind a double click event to the cells of the first column. Populating is not the problem, I just used

idNumber.setCellValueFactory(new PropertyValueFactory<LiveStock, String>("idNumber"));
status.setCellValueFactory(new PropertyValueFactory<LiveStock, String>("status"));

然后我用Google搜索了解如何将doubleclick事件绑定到表格的单元格并找到 javafx,TableView:检测单元格上的双击
等等...
我定义了一个这样的自定义cellFactory:

I then googled around to figure out how to bind a doubleclick event to the cells of the table and found javafx, TableView: detect a doubleclick on a cell amongst others... I defined a custom cellFactory like this:

Callback<TableColumn<LiveStock, String>, TableCell<LiveStock, String>> cellFactory =
    new Callback<TableColumn<LiveStock, String>, TableCell<LiveStock, String>>() {
        @Override
        public TableCell call(TableColumn p) {
            TableCell cell = new TableCell<LiveStock, String>() {};

            cell.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent event) {
                    if (event.getClickCount() == 2) {
                        System.out.println("double clicked!");
                        TableCell c = (TableCell) event.getSource();
                        System.out.println("Livestock ID: " + c.getId());
                    }
                }
            });

            return cell;
        }

我删除了更新 toString 方法只是为了看看我们遇到问题的原因。

I removed the update and toString methods just to see if they where the reason I ran in to problems.

所以我试过

idNumber.setCellFactory(cellFactory);
idNumber.setCellValueFactory(new PropertyValueFactory<LiveStock, String>("idNumber"));

这导致我的单元格变空,但双击绑定

This results in my cells beeing empty, but having the double click binding

任何想法?

我的LiveStock课程如下所示:

My LiveStock class looks like this:

package projekt1.fx;

import javafx.beans.property.SimpleStringProperty;

public class LiveStock {
    private final int idNumber;
    private final SimpleStringProperty ownerID;
    private SimpleStringProperty status;
    private double lat;
    private double longd;


    public LiveStock(int idNumber, String ownerID) {
        this.idNumber = idNumber;
        this.ownerID = new SimpleStringProperty(ownerID);
        this.status = new SimpleStringProperty("ok");
    }

    public int getIdNumber() {
        return this.idNumber;
    }

//    public void setIdNumber(int number) {
//        this.idNumber = number;
//    }

    public String getOwnerID(){
        return ownerID.get();
    }

    public void setOwnerID(String id){
        ownerID.set(id);
    }

    public String getStatus(){
        return status.get();
    }

    public void setStatus(String st){
        status.set(st);
    } 
}






现在,cellfactory看起来像这样:


The cellfactory now looks like this:

    Callback<TableColumn<LiveStock, String>, TableCell<LiveStock, String>> cellFactory =
        new Callback<TableColumn<LiveStock, String>, TableCell<LiveStock, String>>() {
            @Override
            public TableCell call(TableColumn p) {
                TableCell cell = new TableCell<LiveStock, String>() {
                    @Override
                    public void updateItem(String item, boolean empty) {
                        super.updateItem(item, empty);
//                        setText("HELLO WORLD!");
                        setText(empty ? null : getString());
                    }
                };

                cell.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent event) {
                        if (event.getClickCount() == 2) {
                            System.out.println("double clicked!");
                            TableCell c = (TableCell) event.getSource();
                            System.out.println("Livestock ID: " + c.getId());
                            togglePopup(null);
                        }
                    }
                });

                return cell;
            }
        };


推荐答案

Cell API 说:


因为到目前为止,单元格最常见的用例是向
用户显示文本,此用例专门针对Cell内部进行了优化。这是由 Labeled 延伸的Cell完成的
。这意味着
Cell的子类只需设置文本属性,而不是创建单独的
Label并在Cell中设置它。 ...

Because by far the most common use case for cells is to show text to a user, this use case is specially optimized for within Cell. This is done by Cell extending from Labeled. This means that subclasses of Cell need only set the text property, rather than create a separate Label and set that within the Cell. ...

当前 Cell构造函数的源代码将文本设置为null:

The current source code of Cell constructor sets the text to null:

public Cell() {
    setText(null);
    ...
}

子类 IndexedCell 和子子类 TableCell ,它们都没有设置 Labeled 的文本。$
源代码中默认单元格工厂 TableColumn 设置文本。

The subclass IndexedCell and sub-subclass TableCell, both of them don't set the text of Labeled.
The text is set by default cell factory of TableColumn in source code.

public static final Callback<TableColumn<?,?>, TableCell<?,?>> DEFAULT_CELL_FACTORY = new Callback<TableColumn<?,?>, TableCell<?,?>>() {
    @Override public TableCell<?,?> call(TableColumn<?,?> param) {
        return new TableCell() {
            @Override protected void updateItem(Object item, boolean empty) {
                if (item == getItem()) return;

                super.updateItem(item, empty);

                if (item == null) {
                    super.setText(null);
                    super.setGraphic(null);
                } else if (item instanceof Node) {
                    super.setText(null);
                    super.setGraphic((Node)item);
                } else {
                    super.setText(item.toString());
                    super.setGraphic(null);
                }
            }
        };
    }
};

但是,通过定义自己的单元工厂来创建新的 TableCell 但未在其覆盖 updateItem()方法中设置文本,将产生一个空(= null)列单元格文本。所以是的,问题的原因是删除 updateItem 方法,它在内部调用 setText(...)

However by defining your own cell factory that creates new TableCell but does not set the text in its overriden updateItem() method, will be resulting an empty (=null) column cell text. So yes the reason of the problem was removing updateItem method, which calls setText(...) internally.

编辑:

为TableColumns明确指定泛型类型,


Specify the generic types explicitly for TableColumns as,

TableColumn<LiveStock, Integer> idNumber = new TableColumn<LiveStock, Integer>("ID No");

这将避免类型不匹配或错误的类型转换。

然后是细胞工厂您的用例的回调将是

This will avoid type mismatches or wrong type castings.
Then the cell factory callback for your use case will be

Callback<TableColumn<LiveStock, Integer>, TableCell<LiveStock, Integer>> cellFactory =
        new Callback<TableColumn<LiveStock, Integer>, TableCell<LiveStock, Integer>>() {
    public TableCell<LiveStock, Integer> call(TableColumn<LiveStock, Integer> p) {
        TableCell<LiveStock, Integer> cell = new TableCell<LiveStock, Integer>() {

            @Override
            public void updateItem(Integer item, boolean empty) {
                super.updateItem(item, empty);
                setText((item == null || empty) ? null : item.toString());
                setGraphic(null);
            }
        };

        cell.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if (event.getClickCount() > 1) {
                    System.out.println("double clicked!");
                    TableCell c = (TableCell) event.getSource();
                    System.out.println("Cell text: " + c.getText());
                }
            }
        });
        return cell;
    }
};

改变了什么?

LiveStock中idNumber的类型是 INT 。通过定义 new TableColumn< LiveStock,Integer> 我们说这是来自LiveStock行的列,其属性idNumber具有int类型,但泛型类型必须是引用类型,它不能 TableCell< LiveStock,int> 所以我们定义 TableCell< LiveStock,Integer> 。规则的大拇指:行项类的属性类型应该与TableColumn的第二个泛型类型参数匹配,并且由此也是TableCell的参数。

What is changed?
The type of idNumber in LiveStock is int. By defining new TableColumn<LiveStock, Integer> we say this is a column from LiveStock row for its attribute idNumber which has a type int, but the generic types must be a reference type, it cannot be TableCell<LiveStock, int> so we define TableCell<LiveStock, Integer>. The thumb of rule: row item class's attribute type should match the second generic type parameter of TableColumn and due to this the parameter of TableCell also.

getString方法在引用的答案链接由您提及。但它只是一个用户定义的方法,不是强制使用它。

getString method is defined in the referenced answer link mentioned by you. But it is just a user defined method, not mandatory to use it.

这篇关于自定义Java-fx cellfactory混淆了setCellValueFactory的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆