Java FX Circle Image

I hope you can help me. I'm trying to round a image retrieved from my database. In the next image you can see the image is correctly displayed in a imageview. User selects a new item in the table and the image change to display the correct image, this is working, no problems here.

This is the program

I try with this code in the gestionarEventos :

imgfotovisi.imageProperty().bind(imageRetrievalService.valueProperty());
        Image im = imgfotovisi.getImage();
        circulo.setFill(new ImagePattern(im));

But java say :

... 58 more
Caused by: java.lang.NullPointerException: Image must be non-null.
    at javafx.scene.paint.ImagePattern.<init>(ImagePattern.java:235)

The program runs if I delete the lines below the

imgfotovisi.imageProperty().bind(imageRetrievalService.valueProperty()); 

line.

When it runs, I don't know why says the image is null, when I can see clearly there.

This is ver_visitantes class:

   import java.net.URL;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.util.ResourceBundle;
    import java.util.function.Predicate;
    import javafx.beans.property.ReadOnlyStringWrapper;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.collections.transformation.FilteredList;
    import javafx.collections.transformation.SortedList;
    import javafx.concurrent.Service;
    import javafx.concurrent.Task;
    import javafx.event.ActionEvent;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.Node;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableView;
    import javafx.scene.control.TextField;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.input.InputEvent;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
    import javafx.scene.paint.ImagePattern;
    import javafx.scene.shape.Circle;

    import javafx.stage.Stage;

    public class ver_visitantes implements Initializable {

        @FXML   private TableView<visitantes> tbvisitantes;
        @FXML   private TableColumn<visitantes, String> clcedula,clnombres,clapellidos,clapartamento,clcelular,clobservaciones;
        @FXML   private ImageView imgfotovisiact,imgfotoact,imgfotovisi,imgfoto;
        @FXML   private TextField txtcedula,txtnombres,txtapto,txtapellidos,txtapt,txtcelular,txtobservaciones;
        @FXML   private Label lblinfovisiact,lblusuario,lblstatusvisi;
        @FXML   private Circle circulo;

        private ObservableList<visitantes> visitorlist;

        @Override
        public void initialize(URL arg0, ResourceBundle arg1) {


            ConexionSQL cnt = new ConexionSQL();
            cnt.conexion();

            visitorlist = FXCollections.observableArrayList();
            visitantes.llenarlistavisitas(cnt.conexion(), visitorlist);
            tbvisitantes.setItems(visitorlist);// llenar table view con la lista

            clcedula.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getcedula()));
            clnombres.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getnombres()));
            clapellidos.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getapellidos()));
            clapartamento.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getapartamento()));
            clcelular.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getcelular()));
            clobservaciones.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getobservaciones()));

            gestionarEventos();

            tbvisitantes.getSelectionModel().selectFirst();


        }

        public void gestionarEventos() { 
            tbvisitantes.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<visitantes>() {
                @Override
                public void changed(ObservableValue<? extends visitantes> arg0, visitantes valorAnterior,
                        visitantes valorSeleccionado) {
                    imgfoto.setVisible(false);
                    btnmodificar.setDisable(false);
                    btncancelar.setDisable(false);
                    btneliminar.setDisable(false);
                    imageRetrievalService.restart();

                    if (valorSeleccionado != null) {

                        txtcedula.setText(String.valueOf(valorSeleccionado.getcedula()));
                        txtnombres.setText(valorSeleccionado.getnombres());
                        txtapellidos.setText(valorSeleccionado.getapellidos());
                        txtapto.setText(String.valueOf(valorSeleccionado.getapartamento()));
                        txtcelular.setText(String.valueOf(valorSeleccionado.getcelular()));
                        txtobservaciones.setText(String.valueOf(valorSeleccionado.getobservaciones()));
                    }
                }
            });

        imgfotovisi.imageProperty().bind(imageRetrievalService.valueProperty());

         }


        private final Service<Image> imageRetrievalService = new Service<Image>() {// cargar imagen en visitantes
            @Override
            protected Task<Image> createTask() {
                final String id;

                final visitantes visitante = tbvisitantes.getSelectionModel().getSelectedItem();
                if (visitante == null) {
                    id = null;
                } else {
                    id = visitante.getcedula();
                }
                return new Task<Image>() {
                    @Override
                    protected Image call() throws Exception {
                        if (id == null) {
                            return null;
                        }
                        return visitante.getImageById(id);
                    }
                };
            }
        };


    }

this is the visitantes class,called from the imageRetrievalService to get the image:

package application;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;



import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.scene.image.Image;


public class visitantes {
    private StringProperty cedula;
    private StringProperty nombres;
    private StringProperty apellidos;
    private StringProperty apartamento;
    private StringProperty celular;
    private StringProperty observaciones;



    public visitantes(String cedula,String nombres,String apellidos,String apartamento,String celular,String observaciones){

        this.cedula = new SimpleStringProperty(cedula);
        this.nombres = new SimpleStringProperty(nombres);
        this.apellidos = new SimpleStringProperty(apellidos);
        this.apartamento = new SimpleStringProperty(apartamento);
        this.celular = new SimpleStringProperty(celular);
        this.observaciones = new SimpleStringProperty(observaciones);



    }




    public String getnombres(){
        return nombres.get();
    }

    public void setnombres(String nombres){
        this.nombres = new SimpleStringProperty(nombres);
    }

    public String getcedula(){
        return cedula.get();
    }

    public void setcedula(String cedula){
        this.cedula = new SimpleStringProperty(cedula);
    }
    public String getapellidos(){
        return apellidos.get();
    }

    public void setapellidos(String apellidos){
        this.apellidos = new SimpleStringProperty(apellidos);
    }

    public String getapartamento(){
        return apartamento.get();
    }

    public void setapartamento(String apartamento){
        this.apartamento = new SimpleStringProperty(apartamento);
    }

    public String getcelular(){
        return celular.get();
    }

    public void setcelular(String celular){
        this.celular = new SimpleStringProperty(celular);
    }




            public Image getImageById(String id) throws SQLException, IOException  {
                try (
                        ConexionSQL cn = new ConexionSQL();
                        Connection con = cn.conexion();
                    PreparedStatement ps = con.prepareStatement(
                        "SELECT foto_visi FROM visitantes WHERE cedula_visi = ?");
                ) {
                    ps.setString(1, id);
                    ResultSet results = ps.executeQuery();
                    Image img = null ;
                    if (results.next()) {
                        Blob foto = results.getBlob("foto_visi");
                        InputStream is = foto.getBinaryStream();
                        img = new Image(is) ; // false = no background loading 
                        is.close();
                    }
                    results.close();
                    return img ;
                } catch (Throwable e) {
                    String info = e.getMessage();
                    System.out.println(info);
                }
                return null;
            }
   }

I think the problem is here:

imgfotovisi.imageProperty().bind(imageRetrievalService.valueProperty());

I don't know if the retrieved image is loaded in the imageivew in this line. Looks like yes, but if I do

Image im = imgfotovisi.getImage();

Java says it is null. Then I can't get the image into the circle.

Thanks in advance :)

Upvotes: 1

Views: 909

Answers (1)

jewelsea
jewelsea

Reputation: 159281

bind isn't going to load an image itself, it will just bind so that one variable will change when the source changes (in this case the value property of the service), which isn't going to happen straight away as the service is running asynchronously. So, if you query the value straight away after issuing the bind statement, you won't get the result you are expecting, as the source hasn't yet changed.

Instead you need to take action only once the image is actually available.

For instance:

imageRetrievalService.valueProperty().addListener((obs, oldVal, newVal) ->
    if (newVal != null) 
        circulo.setFill(new ImagePattern(newVal))
);

Or, if you don't want a direct linkage to the service, and given that the imgfotovsi image property is already bound to the service value:

imgfotovisi.imageProperty().addListener((obs, oldVal, newVal) ->
    if (newVal != null) 
        circulo.setFill(new ImagePattern(newVal))
);

Upvotes: 2

Related Questions