当对象是类型时,在tableview上显示图像

时间:2015-01-13 15:32:13

标签: java javafx

首先,对不起我的英语,感谢您阅读..: - )

我有一个tableview,它显示了一个名为Produto的类的信息。

该表有一列显示一个名为produto的图像,但我只需要为某种类型的Produto显示此图像。

Produto课程:

public class Produto {

   private Integer id;
   private String nome;
   private Tipo type;


   //get set..

}

表格列:

TableColumn<Produto,String> tbcNomeProduto = new TableColumn<Produto,String>();

tbcNomeProduto.setCellValueFactory(new PropertyValueFactory<Produto, String>("nome"));
        tbcNomeProduto.setCellFactory(new Callback<TableColumn<Produto,String>,TableCell<Produto,String>>(){        
            @Override
            public TableCell<Produto, String> call(TableColumn<Produto, String> param) {                
                TableCell<Produto, String> cell = new TableCell<Produto, String>(){



                    @Override
                    public void updateItem(String item, boolean empty) {                        

                        if(item != null){

                            HBox box= new HBox();
                            box.setSpacing(10);
                            VBox vbox = new VBox();
                            vbox.getChildren().add(new Label(item));

                            ImageView imageview = new ImageView();
                            imageview.setImage(new Image(getClass().getResourceAsStream("16x16.png"))); 

                            box.getChildren().addAll(imageview,vbox); 

                            setGraphic(box);
                        }
                    }
                };

                return cell;
            }

        });

如何访问updateItem中的当前Produto对象,获取Produto的类型并选择是否显示表格中的图像?

1 个答案:

答案 0 :(得分:1)

我通常采用的方法是使表列的类型与表的类型相同:

TableColumn<Produto, Produto> tbcNomeProduto = new TableColumn<>();

原因是此列中单元格中显示的值取决于两件事:Produto.nomeProduto.type;换句话说,此列中的单元格是Produto.nomeProduto.type的视图。因此,包含显示单元格所需的所有数据的最小实体(即单元格是视图的最小实体)是Produto实例本身。

所以现在我会做

tbcNomeProduto.setCellValueFactory(new Callback<CellDataFeatures<Produto, Produto>, ObservableValue<Produto>>() {
    @Override
    public ObservableValue<Produto> call(CellDataFeatures<Produto, Produto> data) {
        return new ReadOnlyObjectWrapper<>(data.getValue());
    }
});
tbcNomeProduto.setCellFactory(new Callback<TableColumn<Produto, Produto>, TableCell<Produto, Produto>>() {
    @Override
    public TableCell<Produto, Produto> call(TableColumn<Produto, Produto> col) {
        return new TableCell<Produto, Produto>() {

            private HBox hbox = new HBox();
            private ImageView imageView = new ImageView(new Image(getClass().getResourceAsStream("16x16.png")));
            private Label label = new Label();

            // anonymous constructor:
            {
                setGraphic(hbox);
                setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
            }

            @Override
            public void updateItem(Produto item, boolean empty) {
                super.updateItem(item, empty);

                hbox.getChildren().clear();
                if (item != null) {
                    Tipo type = item.getType();
                    String nome = item.getNome();
                    if (/* should show image...*/) {
                        hbox.getChildren().add(imageView);
                    }
                    hbox.getChildren().add(label);
                }
            }
        };
    }
});

在您的示例中,您的Produto类是POJO,遵循标准JavaBean约定,而不使用可观察的JavaFX属性。因此,如果要为显示的nome实例更改Produto字段,则无论如何都无法更新表,因为nome字段无法观察。

如果你在Produto类中有可观察的字段,并且在显示对象时这些值可能会发生变化,那么你需要在表格单元格中做更多的工作。这是因为nome字段可能会在Produto实例没有更改的情况下发生变化;后者意味着不会调用updateItem(...)方法。我希望包含代码来管理可能遇到此问题的其他读者,即使它与手头的问题无关。为此使用匿名内部类会非常难看,因此我将恢复为Java 8代码并在此部分使用lambda表达式。

假设Produto类看起来像

public class Produto {
    private final StringProperty nome = new SimpleStringProperty();
    public StringProperty nomeProperty() {
        return nome ;
    }
    public final String getNome() {
        return nomeProperty().get();
    }
    public final void setNome(String nome) {
        nomeProperty().set(nome);
    }

    private final ObjectProperty<Tipo> type = new SimpleObjectProperty<>() ;
    // get/set and property accessor methods as above....

    private final IntegerProperty id = new SimpleIntegerProperty();
    // get/set and property accessor methods...
}

如上所述

TableColumn<Produto, Produto> tbcNomeProduto = new TableColumn<>();
tbcNomeProduto.setCellValueFactory(cellData -> new ReadOnlyPropertyWrapper<>(cellData.getValue()));

对于单元工厂,您需要为各个属性创建侦听器。当显示的Produto发生更改时注册并取消注册这些属性:

tbc.setCellFactory(col -> {
    Label label = new Label();
    ImageView imageView = new ImageView(new Image(getClass().getResourceAsStream("16x16.png")));
    HBox hbox = new HBox();

    TableCell<Produto, Produto> cell = new TableCell<>();
    // listener for the nome property changing:
    ChangeListener<String> nomeListener = (obs, oldNome, newNome) -> label.setText(newNome);
    // listener for type property changing:
    ChangeListener<Tipo> typeListener = (obs, oldType, newType) -> {
        if ( /* should show image */) {
            hbox.getChildren().setAll(imageView, label);
        } else {
            hbox.getChildren().setAll(label);
        }
    }
    cell.itemProperty().addListener((obs, oldProduto, newProduto) -> {
        if (oldProduto != null) {
            oldProduto.nomeProperty().removeListener(nomeListener);
            oldProduto.typeProperty().removeListener(typeListener);
        }
        if (newProduto == null) {
            cell.setGraphic(null);
        } else {
            label.setText(newProduto.getNome());
            Tipo type = newProduto.getType();
            if (/* should show graphic */) {
                hbox.getChildren().setAll(imageView, label);
            } else {
                hbox.getChildren().setAll(label);
            }
            cell.setGraphic(hbox);
            newProduto.nomeProperty().addListener(nomeListener);
            newProduto.typeProperty().addListener(typeListener);
        }
    });
    cell.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
    return cell ;
});

这很容易概括地在不同条件下显示不同的图像,甚至可以操纵单元格的css样式等。