Flavio
Flavio

Reputation: 61

JAVAFX: update a listview with image + text

I am trying to create a simple chess game with javafx. I have 2 listview filled with images and a counter near each image, which represent the counter of each piece that is removed from the chessboard. Is there a way to update the counter of an image? This is the code I ued to create the starting list, with al the pieace with 0x counter.

        lista2.setCellFactory(listview -> new ListCell<String>() {
        private ImageView imageView = new ImageView();
        @Override
        public void updateItem(final String item, final boolean empty) {
            Image img = null;
            super.updateItem(item, empty);
            if (empty) {
                setGraphic(null);
            } else {
                try(InputStream is = Files.newInputStream(Paths.get(GameView.RESFOLDER + item + GameView.FORMAT))){
                    img = new Image(is);                
                } catch(IOException e) {
                    System.out.println("Couldn't load image" + Paths.get(GameView.RESFOLDER + item + GameView.FORMAT));
                }        
                // true makes this load in background
                // see other constructors if you want to control the size, etc 
                imageView.setImage(img);
                setGraphic(imageView);
                setText("x0");
            }
        }
    });

Upvotes: 0

Views: 1903

Answers (1)

Zephyr
Zephyr

Reputation: 10253

You are doing too much within your updateItem() method for the ListView. You should instead use a proper data model object to populate the ListView.

You should be updating the underlying object instead of doing any kind of calculations and such within the CellFactory.

Here is a quick sample application to demonstrate. You'll see I have created a separate class for a ChessPiece. That object contains all the information you need to be displayed in the ListView.

Then, within our CellFactory, you just update the displayed item using the values from the ChessPiece.

THE CODE

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        // Build a simple UI
        VBox root = new VBox(5);
        root.setPadding(new Insets(10));
        root.setAlignment(Pos.CENTER);

        // Create a list of Chess pieces
        ObservableList<ChessPiece> chessPieces = FXCollections.observableArrayList();

        // Add a sample Chess piece, a queen in this case
        chessPieces.add(new ChessPiece(
                "Queen",
                new ImageView("sample/listViewImages/queen.png"),
                0
        ));

        // Create the ListView
        ListView<ChessPiece> lvChessPieces = new ListView<>();

        // Setup the CellFactory
        lvChessPieces.setCellFactory(listView -> new ListCell<ChessPiece>() {
            @Override
            protected void updateItem(ChessPiece piece, boolean empty) {
                super.updateItem(piece, empty);

                if (empty) {
                    setGraphic(null);
                } else {

                    // Create a HBox to hold our displayed value
                    HBox hBox = new HBox(5);
                    hBox.setAlignment(Pos.CENTER);

                    // Add the values from our piece to the HBox
                    hBox.getChildren().addAll(
                            piece.getImage(),
                            new Label(piece.getName()),
                            new Label("x " + piece.getCount())
                    );

                    // Set the HBox as the display
                    setGraphic(hBox);
                }
            }
        });

        // Bind our list of pieces to the ListView
        lvChessPieces.setItems(chessPieces);

        // Create a button to add change the Queen count
        Button button = new Button("Add a Queen");
        button.setOnAction(e -> {
            // Get the queen from the list of Chess Pieces. For this sample we only have one piece in our List,
            // but in a real application, you'll need to build a method for retrieving the correct piece.
            ChessPiece queen = chessPieces.get(0);
            queen.setCount(queen.getCount() + 1);

            // Refresh the ListView to show the updated counts
            lvChessPieces.refresh();
        });

        root.getChildren().addAll(lvChessPieces, button);
        primaryStage.setScene(new Scene(root));

        primaryStage.show();
    }
}

/**
 * Defines a Chess piece, including it's name, image, and current count
 */
class ChessPiece {

    private final String name;
    private final ImageView image;
    private int count;

    public ChessPiece(String name, ImageView image, int count) {
        this.name = name;
        this.image = image;
        this.count = count;

        // Resize the image, if necessary
        this.image.setFitHeight(25);
        this.image.setFitWidth(20);

    }

    public String getName() {
        return name;
    }

    public ImageView getImage() {
        return image;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

THE RESULTS

Here is a screenshot of what this application produces:

Screenshot

Upvotes: 4

Related Questions