Nacira
Nacira

Reputation: 76

How to retreive image (byte type) from database to tableview (imageView)/ JavaFx

I have two different types (byte to Model and imageView to View) so I had to use two classes "ProductTableColumnModel" (help class for the picture column ) & Model "Product"

pictureColumn.setCellValueFactory(new PropertyValueFactory<ProductTableColumnModel, ImageView>("picture"));

but other columns like this:

descColumn.setCellValueFactory(new PropertyValueFactory<Product, String>("description"));

Product class:

public class Product {


private byte[] picture;

@Column(name= "picture")
public byte[] getPicture() {
    return this.picture;
}

public void setPicture(byte[] picture) {
    
    this.picture = picture;
}
}

ProductTableColumnModel class:

public class ProductTableColumnModel {


private ImageView picture;


public ImageView getPicture() {
    return this.picture;
}

public void setPicture(ImageView picture) {
    this.picture = picture;
}

in ProductViewController class:

@FXML
TableView <Product> table_Products;

@FXML
TableColumn <Product, String> productName;

@FXML
TableColumn <Product, String> descColumn;

@FXML
TableColumn <ProductTableColumnModel, ImageView> pictureColumn;

.....

// show data in TableView
for(Product  p : getProducts() ) {
        
        Product product = new Product();
        
        product.setProductName(String.valueOf(p.getProductName() ));
        product.setDescription(String.valueOf(p.getDescription()));
        
        byte[] pictureImageInByte = p.getPicture(); 
        
        if(pictureImageInByte != null) {
            
            ByteArrayInputStream imageDate = new ByteArrayInputStream(pictureImageInByte);
            
            Image image = new Image(imageDate);
            
            /* ???????

            */
        }
        tableData.addAll(product);
    }
    /* set table items */
    table_Products.setItems(tableData);
private void intializeTableColumns() {
    
    
    tableData = FXCollections.observableArrayList();
    
    productName.setCellValueFactory(new PropertyValueFactory<Product, String>("productName"));
    
    descColumn.setCellValueFactory(new PropertyValueFactory<Product, String>("description"));
    
    pictureColumn.setCellValueFactory(new PropertyValueFactory<ProductTableColumnModel, ImageView>("picture"));
    

}

Can anyone help me to write the correct code after this?

if(pictureImageInByte != null) {

        ByteArrayInputStream imageDate = new ByteArrayInputStream(pictureImageInByte);

        Image image = new Image(imageDate);

        /* ???????

        */
    }

Upvotes: 2

Views: 127

Answers (1)

James_D
James_D

Reputation: 209603

If you have a TableView<Product>, then every column has to be a TableColumn<Product, T> for some T.

T can be different for each column, but should always be a "data type", never a "UI type" (i.e. it should never be a subclass of Node).

Here you should have

@FXML
TableColumn <Product, byte[]> pictureColumn;

because the data you are displaying in each cell in the column is a byte[].

You can use a cellFactory, which in general describes how to display the cell's data, to create the ImageView to display in the cells in the column. If the image data are raw data, e.g. in rgb format, you might do:

private void intializeTableColumns() {

    // ...

    pictureColumn.setCellValueFactory(cellData -> 
        new SimpleObjectProperty<>(cellData.getValue().getPicture()));

    // or
    // pictureColumn.setCellValueFactory(new PropertyValueFactory<>("picture"));
    // but the previous version is much better

    pictureColumn.setCellFactory(col -> new TableCell<>() {
        private WritableImage image = new WritableImage(WIDTH, HEIGHT);
        private ImageView imageView = new ImageView(image);

        @Override
        protected void updateItem(byte[] imageData, boolean empty) {
            super.updateItem(imageData, empty) ;
            if (empty || imageData == null) {
                setGraphic(null);
            } else {
                PixelWriter pw = image.getPixelWriter();
                // modify the following as needed if you have a different format
                PixelFormat<ByteBuffer> format = PixelFormat.getByteRgbInstance();
                pw.setPixels(0, 0, WIDTH, HEIGHT, format, imageData, 0, 3*WIDTH);
                setGraphic(imageView);
            }
        }
    });

    // ...
}

Obviously you need to fill in some information here, such as the width and height of the images (which I've just assumed are constant), and modify it depending on how the image is encoded in the byte[] array.

If the image data are in a recognized format, i.e. BMP, GIF, JPEG, or PNG, you can do:

    pictureColumn.setCellFactory(col -> new TableCell<>() {
        private ImageView imageView = new ImageView();

        @Override
        protected void updateItem(byte[] imageData, boolean empty) {
            super.updateItem(imageData, empty) ;
            if (empty || imageData == null) {
                setGraphic(null);
            } else {
                Image image = new Image(new ByteArrayInputStream(imageData));
                imageView.setImage(image);
                setGraphic(imageView);
            }
        }
    });

Upvotes: 3

Related Questions