【问题标题】:Custom Java-fx cellfactory messes up the setCellValueFactory自定义 Javafx 单元工厂弄乱了 setCellValueFactory
【发布时间】:2013-10-15 06:21:40
【问题描述】:

在搞砸了 Netbeans 和 Scenebuilder 一段时间后,我遇到了一个我不太明白的问题。我使用自定义cellfactory 将双击事件绑定到我的表格视图中的单元格。但是当我将 cellfactory 和设置为 cellValueFactory 时,只有自定义 cellFactory 才有效果。

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

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

然后我用谷歌搜索了如何将双击事件绑定到表格的单元格并找到javafx, TableView: detect a doubleclick on a cell 在其他人中... 我这样定义了一个自定义 cellFactory:

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

我删除了 update 和 toString 方法只是为了看看它们是否是我遇到问题的原因。

所以我尝试了

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

这导致我的单元格为空,但具有双击绑定

有什么想法吗?

我的 LiveStock 类如下所示:

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

细胞工厂现在看起来像这样:

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

【问题讨论】:

  • 也发布您的 LiveStock 课程。它有 idNumber 的访问器吗?

标签: javafx tableview cell double-click


【解决方案1】:

Cell API 的文档说:

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

当前source code of Cell constructor将文本设置为null:

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

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

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(...)。

编辑:
为 TableColumns 显式指定泛型类型,

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

这将避免类型不匹配或错误的类型转换。
然后,您的用例的单元工厂回调将是

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&lt;LiveStock, Integer&gt;,我们说这是LiveStock 行中的一列,其属性idNumber 的类型为int,但泛型类型必须是引用类型,它不能是TableCell&lt;LiveStock, int&gt;,所以我们定义TableCell&lt;LiveStock, Integer&gt;。规则的要点:行项目类的属性类型应该匹配 TableColumn 的第二个泛型类型参数,因此也匹配 TableCell 的参数。

getString 方法在您提到的参考答案链接中定义。但它只是一个用户定义的方法,并不强制使用它。

【讨论】:

  • Uluk 的解释真的很好。
  • 好的,谢谢。现在我明白了这个问题,但不是很清楚如何解决它。我在cellFactory 中添加了一个updateItem 方法,但如果我只是从[链接] stackoverflow.com/questions/12499269/… 复制一个,我会得到 找不到符号。符号:方法 getString()。如果我向setText 添加一个静态字符串,它就可以工作。那么如何告诉setText 方法获取每个LiveStock 对象的IdNumber?
  • @Uluk:再次感谢您的快速回答。我尝试了提供的setTest 方法,但我的单元格中仍然没有文本。我在想updateItem 中的item 参数如何知道 LiveStock 对象中的哪些变量应该从中获取字符串?它得到了它:idNumber.setCellValueFactory(new PropertyValueFactory&lt;LiveStock, String&gt;("idNumber")); 但我在那儿指定了“idNumber”。我在自定义 cellFactory 中使用:TableCell cell = new TableCell&lt;LiveStock, String&gt; 连接到 LiveStock,但从未连接到 IdNumber 字段。
  • 你好。我已经离开一段时间了。我填充了单元格,它们具有双击功能。耶!但我从来没有让它与定制的细胞工厂一起工作。我最终得到了自定义和idNumber.setCellValueFactory(new PropertyValueFactory&lt;LiveStock, Integer&gt;("idNumber")); 非常感谢您的帮助!
猜你喜欢
  • 2016-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-27
  • 2012-05-18
  • 1970-01-01
相关资源
最近更新 更多