Java (JFoenix)JFXTreeTableView如何显示/组合图像+;列中的字符串?

Java (JFoenix)JFXTreeTableView如何显示/组合图像+;列中的字符串?,java,javafx,jfoenix,Java,Javafx,Jfoenix,我试图让JFXTreeTableView列同时显示文本和图像,同时继续使用树分组功能 我在演示后对我的程序进行了建模,并且能够使基于StringProperty的列正常工作,但是现在尝试添加ObjectProperty列就是不起作用。有谁能给我举一个使用JFXTreeTableView的列的例子,以及除了primative或String以外的任何东西(即使用ObjectProperty)的东西 编辑:我刚刚在这方面取得了一些进展,在我能够显示图像和文本的专栏中使用了HBox 下面是我用来达到这个

我试图让JFXTreeTableView列同时显示文本和图像,同时继续使用树分组功能

我在演示后对我的程序进行了建模,并且能够使基于StringProperty的列正常工作,但是现在尝试添加
ObjectProperty
列就是不起作用。有谁能给我举一个使用JFXTreeTableView的列的例子,以及除了primative或String以外的任何东西(即使用
ObjectProperty
)的东西

编辑:我刚刚在这方面取得了一些进展,在我能够显示图像和文本的专栏中使用了HBox

下面是我用来达到这个目的的代码

在我的单元格对象中:

public final class TestObj extends RecursiveTreeObject<TestObj> {
        private final ObjectProperty<HBox> source;

        public TestObj(String source) {
                ImageView iv = new ImageView();
                HBox hbox = new HBox();
                hbox.setSpacing(10);
                VBox vbox = new VBox();
                Label l = new Label(source);
                vbox.getChildren().add(l);
                iv.setFitHeight(20);
                iv.setFitWidth(20);
                iv.setImage(new Image("/images/test.png"));
                l.setGraphic(iv);
                hbox.getChildren().addAll(vbox);
                this.source = new SimpleObjectProperty<>(hbox);
        }

        // ... getters & setters
}
public void initialize(URL location, ResourceBundle resources) {
        JFXTreeTableColumn<TestObj, HBox> srcColumn = new JFXTreeTableColumn<>("Source");
        srcColumn.setPrefWidth(150);
        srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<TestObj, HBox> x) ->
        srcColumn.validateValue(x) ? x.getValue().getValue().sourceProperty() : srcColumn.getComputedValue(x));

        //... reset of table setup code
}
public final class TestObj extends RecursiveTreeObject<TestObj> {
        //inapplicable vars omitted from this class
        //so don't ask why there's just an inner class here ;)
        private final ObjectProperty<Register> source;
        private final ObjectProperty<Register> destination;

        public TestObj(String src, String srcPort, String srcCountry, String dst, String dstPort, String dstCountry) {
                this.source = new SimpleObjectProperty<>(new Register(src, srcPort, srcCountry));
                this.destination = new SimpleObjectProperty<>(new Register(dst, dstPort, dstCountry));
        }

        // ... getters & setters

        public class Register {
                private final String address;
                private final String port;
                private final String country;

                public Register(String address, String port, String country) {
                    this.address = address;
                    this.port = port;
                    this.country = country;
                }

                //getters ...
         }
}
public void initialize(URL location, ResourceBundle resources) {
        JFXTreeTableColumn<TestObj, TestObj.Register> srcColumn = new JFXTreeTableColumn<>("Source");
        srcColumn.setPrefWidth(150); srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<TestObj, TestObj.Register> x) ->
            srcColumn.validateValue(x) ? x.getValue().getValue().sourceProperty() : srcColumn.getComputedValue(x));
    srcColumn.setCellFactory(new Callback<TreeTableColumn<TestObj, TestObj.Register>, TreeTableCell<TestObj, TestObj.Register>>() {
        @Override
        public TreeTableCell<TestObj, TestObj.Register> call(TreeTableColumn<TestObj, TestObj.Register> param) {
            return new JFXTreeTableCell<TestObj, TestObj.Register>() {
                ImageView iv = new ImageView();
                @Override
                protected void updateItem(TestObj.Register item, boolean empty) {
                    if(item != null) {
                        HBox hbox = new HBox();
                        hbox.setSpacing(10);
                        VBox vbox = new VBox();
                        Label l = new Label(item.getAddress() + ":" + item.getPort());
                        vbox.getChildren().add(l);
                        iv.setFitHeight(20);
                        iv.setFitWidth(20);
                        iv.setImage(new Image("/flags/" + item.getCountry() + ".png"));
                        l.setGraphic(iv);
                        hbox.getChildren().addAll(vbox);
                        setGraphic(hbox);
                    } else {
                        setGraphic(null);
                    }
                }
            };
        }
    });
        //... above duplicated for dstColumn
        //... reset of table setup code
}
@Override
public boolean equals(Object o) {
    if(o == this)
        return true;
    if(!(o instanceof Register))
        return false;
    Register r = (Register)o;
    return Objects.equals(address, r.address) 
        && Objects.equals(port, r.port) 
        && Objects.equals(country, r.country);
}

@Override
public int hashCode() {
    return Objects.hash(address, port, country);
}
public final类TestObj扩展了RecursiveTreeObject{
私有财产来源;
公共TestObj(字符串源){
ImageView iv=新的ImageView();
HBox HBox=新的HBox();
hbox.setspace(10);
VBox VBox=新的VBox();
标签l=新标签(来源);
vbox.getChildren().add(l);
iv.安装高度(20);
iv.设置宽度(20);
iv.setImage(新图像(“/images/test.png”);
l、 经纬仪(iv);
hbox.getChildren().addAll(vbox);
this.source=新的SimpleObject属性(hbox);
}
//…接受者和接受者
}
在我的控制器中:

public final class TestObj extends RecursiveTreeObject<TestObj> {
        private final ObjectProperty<HBox> source;

        public TestObj(String source) {
                ImageView iv = new ImageView();
                HBox hbox = new HBox();
                hbox.setSpacing(10);
                VBox vbox = new VBox();
                Label l = new Label(source);
                vbox.getChildren().add(l);
                iv.setFitHeight(20);
                iv.setFitWidth(20);
                iv.setImage(new Image("/images/test.png"));
                l.setGraphic(iv);
                hbox.getChildren().addAll(vbox);
                this.source = new SimpleObjectProperty<>(hbox);
        }

        // ... getters & setters
}
public void initialize(URL location, ResourceBundle resources) {
        JFXTreeTableColumn<TestObj, HBox> srcColumn = new JFXTreeTableColumn<>("Source");
        srcColumn.setPrefWidth(150);
        srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<TestObj, HBox> x) ->
        srcColumn.validateValue(x) ? x.getValue().getValue().sourceProperty() : srcColumn.getComputedValue(x));

        //... reset of table setup code
}
public final class TestObj extends RecursiveTreeObject<TestObj> {
        //inapplicable vars omitted from this class
        //so don't ask why there's just an inner class here ;)
        private final ObjectProperty<Register> source;
        private final ObjectProperty<Register> destination;

        public TestObj(String src, String srcPort, String srcCountry, String dst, String dstPort, String dstCountry) {
                this.source = new SimpleObjectProperty<>(new Register(src, srcPort, srcCountry));
                this.destination = new SimpleObjectProperty<>(new Register(dst, dstPort, dstCountry));
        }

        // ... getters & setters

        public class Register {
                private final String address;
                private final String port;
                private final String country;

                public Register(String address, String port, String country) {
                    this.address = address;
                    this.port = port;
                    this.country = country;
                }

                //getters ...
         }
}
public void initialize(URL location, ResourceBundle resources) {
        JFXTreeTableColumn<TestObj, TestObj.Register> srcColumn = new JFXTreeTableColumn<>("Source");
        srcColumn.setPrefWidth(150); srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<TestObj, TestObj.Register> x) ->
            srcColumn.validateValue(x) ? x.getValue().getValue().sourceProperty() : srcColumn.getComputedValue(x));
    srcColumn.setCellFactory(new Callback<TreeTableColumn<TestObj, TestObj.Register>, TreeTableCell<TestObj, TestObj.Register>>() {
        @Override
        public TreeTableCell<TestObj, TestObj.Register> call(TreeTableColumn<TestObj, TestObj.Register> param) {
            return new JFXTreeTableCell<TestObj, TestObj.Register>() {
                ImageView iv = new ImageView();
                @Override
                protected void updateItem(TestObj.Register item, boolean empty) {
                    if(item != null) {
                        HBox hbox = new HBox();
                        hbox.setSpacing(10);
                        VBox vbox = new VBox();
                        Label l = new Label(item.getAddress() + ":" + item.getPort());
                        vbox.getChildren().add(l);
                        iv.setFitHeight(20);
                        iv.setFitWidth(20);
                        iv.setImage(new Image("/flags/" + item.getCountry() + ".png"));
                        l.setGraphic(iv);
                        hbox.getChildren().addAll(vbox);
                        setGraphic(hbox);
                    } else {
                        setGraphic(null);
                    }
                }
            };
        }
    });
        //... above duplicated for dstColumn
        //... reset of table setup code
}
@Override
public boolean equals(Object o) {
    if(o == this)
        return true;
    if(!(o instanceof Register))
        return false;
    Register r = (Register)o;
    return Objects.equals(address, r.address) 
        && Objects.equals(port, r.port) 
        && Objects.equals(country, r.country);
}

@Override
public int hashCode() {
    return Objects.hash(address, port, country);
}
public void初始化(URL位置,ResourceBundle资源){
JFXTreeTableColumn srcColumn=新的JFXTreeTableColumn(“源”);
srcColumn.setPrefWidth(150);
srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures x)->
srcColumn.validateValue(x)?x.getValue().getValue().sourceProperty():srcColumn.getComputedValue(x));
//…重置表格设置代码
}
现在的问题是该列无法正确分组!也就是说:每行的图像和文本可以完全相同,但不会折叠成一组。相反,它会折叠成多个组,每个组有一个元素。这让我想到表格是如何比较单元格的问题。。。也许我需要重写某个方法

编辑2:现在,使用下面的代码,可以进行分组,并正确隐藏未分组的节点。此外,James_D注释用于将GUI元素重新定位到数据类之外。图A和图B显示了当前的问题(在上面段落中概述)

数据对象:

public final class TestObj extends RecursiveTreeObject<TestObj> {
        private final ObjectProperty<HBox> source;

        public TestObj(String source) {
                ImageView iv = new ImageView();
                HBox hbox = new HBox();
                hbox.setSpacing(10);
                VBox vbox = new VBox();
                Label l = new Label(source);
                vbox.getChildren().add(l);
                iv.setFitHeight(20);
                iv.setFitWidth(20);
                iv.setImage(new Image("/images/test.png"));
                l.setGraphic(iv);
                hbox.getChildren().addAll(vbox);
                this.source = new SimpleObjectProperty<>(hbox);
        }

        // ... getters & setters
}
public void initialize(URL location, ResourceBundle resources) {
        JFXTreeTableColumn<TestObj, HBox> srcColumn = new JFXTreeTableColumn<>("Source");
        srcColumn.setPrefWidth(150);
        srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<TestObj, HBox> x) ->
        srcColumn.validateValue(x) ? x.getValue().getValue().sourceProperty() : srcColumn.getComputedValue(x));

        //... reset of table setup code
}
public final class TestObj extends RecursiveTreeObject<TestObj> {
        //inapplicable vars omitted from this class
        //so don't ask why there's just an inner class here ;)
        private final ObjectProperty<Register> source;
        private final ObjectProperty<Register> destination;

        public TestObj(String src, String srcPort, String srcCountry, String dst, String dstPort, String dstCountry) {
                this.source = new SimpleObjectProperty<>(new Register(src, srcPort, srcCountry));
                this.destination = new SimpleObjectProperty<>(new Register(dst, dstPort, dstCountry));
        }

        // ... getters & setters

        public class Register {
                private final String address;
                private final String port;
                private final String country;

                public Register(String address, String port, String country) {
                    this.address = address;
                    this.port = port;
                    this.country = country;
                }

                //getters ...
         }
}
public void initialize(URL location, ResourceBundle resources) {
        JFXTreeTableColumn<TestObj, TestObj.Register> srcColumn = new JFXTreeTableColumn<>("Source");
        srcColumn.setPrefWidth(150); srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<TestObj, TestObj.Register> x) ->
            srcColumn.validateValue(x) ? x.getValue().getValue().sourceProperty() : srcColumn.getComputedValue(x));
    srcColumn.setCellFactory(new Callback<TreeTableColumn<TestObj, TestObj.Register>, TreeTableCell<TestObj, TestObj.Register>>() {
        @Override
        public TreeTableCell<TestObj, TestObj.Register> call(TreeTableColumn<TestObj, TestObj.Register> param) {
            return new JFXTreeTableCell<TestObj, TestObj.Register>() {
                ImageView iv = new ImageView();
                @Override
                protected void updateItem(TestObj.Register item, boolean empty) {
                    if(item != null) {
                        HBox hbox = new HBox();
                        hbox.setSpacing(10);
                        VBox vbox = new VBox();
                        Label l = new Label(item.getAddress() + ":" + item.getPort());
                        vbox.getChildren().add(l);
                        iv.setFitHeight(20);
                        iv.setFitWidth(20);
                        iv.setImage(new Image("/flags/" + item.getCountry() + ".png"));
                        l.setGraphic(iv);
                        hbox.getChildren().addAll(vbox);
                        setGraphic(hbox);
                    } else {
                        setGraphic(null);
                    }
                }
            };
        }
    });
        //... above duplicated for dstColumn
        //... reset of table setup code
}
@Override
public boolean equals(Object o) {
    if(o == this)
        return true;
    if(!(o instanceof Register))
        return false;
    Register r = (Register)o;
    return Objects.equals(address, r.address) 
        && Objects.equals(port, r.port) 
        && Objects.equals(country, r.country);
}

@Override
public int hashCode() {
    return Objects.hash(address, port, country);
}
public final类TestObj扩展了RecursiveTreeObject{
//此类中省略的不适用变量
//所以不要问为什么这里只有一个内部类;)
私有财产来源;
私人最终目的地;
公共TestObj(字符串src、字符串srcPort、字符串srcCountry、字符串dst、字符串dstPort、字符串dstCountry){
this.source=新的SimpleObject属性(新寄存器(src、srcPort、srcCountry));
this.destination=新的SimpleObject属性(新寄存器(dst、dstPort、dstCountry));
}
//…接受者和接受者
公共班级登记册{
私有最终字符串地址;
专用最终字符串端口;
私人国家;
公共寄存器(字符串地址、字符串端口、字符串国家){
this.address=地址;
this.port=端口;
这个国家=国家;
}
//吸气剂。。。
}
}
控制器:

public final class TestObj extends RecursiveTreeObject<TestObj> {
        private final ObjectProperty<HBox> source;

        public TestObj(String source) {
                ImageView iv = new ImageView();
                HBox hbox = new HBox();
                hbox.setSpacing(10);
                VBox vbox = new VBox();
                Label l = new Label(source);
                vbox.getChildren().add(l);
                iv.setFitHeight(20);
                iv.setFitWidth(20);
                iv.setImage(new Image("/images/test.png"));
                l.setGraphic(iv);
                hbox.getChildren().addAll(vbox);
                this.source = new SimpleObjectProperty<>(hbox);
        }

        // ... getters & setters
}
public void initialize(URL location, ResourceBundle resources) {
        JFXTreeTableColumn<TestObj, HBox> srcColumn = new JFXTreeTableColumn<>("Source");
        srcColumn.setPrefWidth(150);
        srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<TestObj, HBox> x) ->
        srcColumn.validateValue(x) ? x.getValue().getValue().sourceProperty() : srcColumn.getComputedValue(x));

        //... reset of table setup code
}
public final class TestObj extends RecursiveTreeObject<TestObj> {
        //inapplicable vars omitted from this class
        //so don't ask why there's just an inner class here ;)
        private final ObjectProperty<Register> source;
        private final ObjectProperty<Register> destination;

        public TestObj(String src, String srcPort, String srcCountry, String dst, String dstPort, String dstCountry) {
                this.source = new SimpleObjectProperty<>(new Register(src, srcPort, srcCountry));
                this.destination = new SimpleObjectProperty<>(new Register(dst, dstPort, dstCountry));
        }

        // ... getters & setters

        public class Register {
                private final String address;
                private final String port;
                private final String country;

                public Register(String address, String port, String country) {
                    this.address = address;
                    this.port = port;
                    this.country = country;
                }

                //getters ...
         }
}
public void initialize(URL location, ResourceBundle resources) {
        JFXTreeTableColumn<TestObj, TestObj.Register> srcColumn = new JFXTreeTableColumn<>("Source");
        srcColumn.setPrefWidth(150); srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<TestObj, TestObj.Register> x) ->
            srcColumn.validateValue(x) ? x.getValue().getValue().sourceProperty() : srcColumn.getComputedValue(x));
    srcColumn.setCellFactory(new Callback<TreeTableColumn<TestObj, TestObj.Register>, TreeTableCell<TestObj, TestObj.Register>>() {
        @Override
        public TreeTableCell<TestObj, TestObj.Register> call(TreeTableColumn<TestObj, TestObj.Register> param) {
            return new JFXTreeTableCell<TestObj, TestObj.Register>() {
                ImageView iv = new ImageView();
                @Override
                protected void updateItem(TestObj.Register item, boolean empty) {
                    if(item != null) {
                        HBox hbox = new HBox();
                        hbox.setSpacing(10);
                        VBox vbox = new VBox();
                        Label l = new Label(item.getAddress() + ":" + item.getPort());
                        vbox.getChildren().add(l);
                        iv.setFitHeight(20);
                        iv.setFitWidth(20);
                        iv.setImage(new Image("/flags/" + item.getCountry() + ".png"));
                        l.setGraphic(iv);
                        hbox.getChildren().addAll(vbox);
                        setGraphic(hbox);
                    } else {
                        setGraphic(null);
                    }
                }
            };
        }
    });
        //... above duplicated for dstColumn
        //... reset of table setup code
}
@Override
public boolean equals(Object o) {
    if(o == this)
        return true;
    if(!(o instanceof Register))
        return false;
    Register r = (Register)o;
    return Objects.equals(address, r.address) 
        && Objects.equals(port, r.port) 
        && Objects.equals(country, r.country);
}

@Override
public int hashCode() {
    return Objects.hash(address, port, country);
}
public void初始化(URL位置,ResourceBundle资源){
JFXTreeTableColumn srcColumn=新的JFXTreeTableColumn(“源”);
srcColumn.setPrefWidth(150);srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures x)->
srcColumn.validateValue(x)?x.getValue().getValue().sourceProperty():srcColumn.getComputedValue(x));
srcColumn.setCellFactory(新回调(){
@凌驾
公共TreeTableCell调用(TreeTableColumn参数){
返回新的JFXTreeTableCell(){
ImageView iv=新的ImageView();
@凌驾
受保护的void updateItem(TestObj.Register项,布尔值为空){
如果(项!=null){
HBox HBox=新的HBox();
hbox.setspace(10);
VBox VBox=新的VBox();
标签l=新标签(item.getAddress()+“:”+item.getPort());
vbox.getChildren().add(l);
iv.安装高度(20);
iv.设置宽度(20);
iv.setImage(新图像(“/flags/”+item.getCountry()+”.png”);
l、 经纬仪(iv);
hbox.getChildren().addAll(vbox);
设置图形(hbox);
}否则{
设置图形(空);
}
}
};
}
});
//…以上为DST列复制
//…重置表格设置代码
}
图A展示了表格的初始视图(此处一切正常)

图B显示了不正确的分组(每个分组应有3个节点)


在回顾了JFoenix的源代码之后,我意识到幕后没有神奇的比较器。。。在我的数据对象中,我只需要重写等值和哈希德方法来考虑复杂对象的变量。 在这种情况下:

public final class TestObj extends RecursiveTreeObject<TestObj> {
        private final ObjectProperty<HBox> source;

        public TestObj(String source) {
                ImageView iv = new ImageView();
                HBox hbox = new HBox();
                hbox.setSpacing(10);
                VBox vbox = new VBox();
                Label l = new Label(source);
                vbox.getChildren().add(l);
                iv.setFitHeight(20);
                iv.setFitWidth(20);
                iv.setImage(new Image("/images/test.png"));
                l.setGraphic(iv);
                hbox.getChildren().addAll(vbox);
                this.source = new SimpleObjectProperty<>(hbox);
        }

        // ... getters & setters
}
public void initialize(URL location, ResourceBundle resources) {
        JFXTreeTableColumn<TestObj, HBox> srcColumn = new JFXTreeTableColumn<>("Source");
        srcColumn.setPrefWidth(150);
        srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<TestObj, HBox> x) ->
        srcColumn.validateValue(x) ? x.getValue().getValue().sourceProperty() : srcColumn.getComputedValue(x));

        //... reset of table setup code
}
public final class TestObj extends RecursiveTreeObject<TestObj> {
        //inapplicable vars omitted from this class
        //so don't ask why there's just an inner class here ;)
        private final ObjectProperty<Register> source;
        private final ObjectProperty<Register> destination;

        public TestObj(String src, String srcPort, String srcCountry, String dst, String dstPort, String dstCountry) {
                this.source = new SimpleObjectProperty<>(new Register(src, srcPort, srcCountry));
                this.destination = new SimpleObjectProperty<>(new Register(dst, dstPort, dstCountry));
        }

        // ... getters & setters

        public class Register {
                private final String address;
                private final String port;
                private final String country;

                public Register(String address, String port, String country) {
                    this.address = address;
                    this.port = port;
                    this.country = country;
                }

                //getters ...
         }
}
public void initialize(URL location, ResourceBundle resources) {
        JFXTreeTableColumn<TestObj, TestObj.Register> srcColumn = new JFXTreeTableColumn<>("Source");
        srcColumn.setPrefWidth(150); srcColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<TestObj, TestObj.Register> x) ->
            srcColumn.validateValue(x) ? x.getValue().getValue().sourceProperty() : srcColumn.getComputedValue(x));
    srcColumn.setCellFactory(new Callback<TreeTableColumn<TestObj, TestObj.Register>, TreeTableCell<TestObj, TestObj.Register>>() {
        @Override
        public TreeTableCell<TestObj, TestObj.Register> call(TreeTableColumn<TestObj, TestObj.Register> param) {
            return new JFXTreeTableCell<TestObj, TestObj.Register>() {
                ImageView iv = new ImageView();
                @Override
                protected void updateItem(TestObj.Register item, boolean empty) {
                    if(item != null) {
                        HBox hbox = new HBox();
                        hbox.setSpacing(10);
                        VBox vbox = new VBox();
                        Label l = new Label(item.getAddress() + ":" + item.getPort());
                        vbox.getChildren().add(l);
                        iv.setFitHeight(20);
                        iv.setFitWidth(20);
                        iv.setImage(new Image("/flags/" + item.getCountry() + ".png"));
                        l.setGraphic(iv);
                        hbox.getChildren().addAll(vbox);
                        setGraphic(hbox);
                    } else {
                        setGraphic(null);
                    }
                }
            };
        }
    });
        //... above duplicated for dstColumn
        //... reset of table setup code
}
@Override
public boolean equals(Object o) {
    if(o == this)
        return true;
    if(!(o instanceof Register))
        return false;
    Register r = (Register)o;
    return Objects.equals(address, r.address) 
        && Objects.equals(port, r.port) 
        && Objects.equals(country, r.country);
}

@Override
public int hashCode() {
    return Objects.hash(address, port, country);
}

你似乎混淆了这件事的不同部分。您的数据类(
TestObj
)不应包含对任何UI组件的任何引用