Yastafari
Yastafari

Reputation: 81

Detecting button click of button added to javafx listview

I am very new to Java so please be patient with me. I have successfully added buttons, labels and even a progress bar to a listview cell. I need to be able to detect when one of the buttons has been clicked. Adding controls to listview content I managed to get from a couple of posts here the code i am using is shown below

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ProgressBar;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.Stage;



public class ListViewDemo extends Application {

  public static class lvCell extends VBox {

    Label labelName = new Label();
    Label labelPath = new Label();
    Label labelElapse = new Label();
    Button buttonPlayPause = new Button();
    Button buttonStop = new Button();
    ImageView ivStop = new ImageView();
    ImageView ivPlay = new ImageView();
    Pane buttonSpacer = new Pane();
    Pane progressBarSpacer = new Pane();

    HBox hbDetail = new HBox();
    HBox hbProgress = new HBox();

    ProgressBar pbProgress = new ProgressBar();

    File filePlay;
    File fileStop;

    double prefWidth = 10;
    double prefHeight = 10;

    lvCell(String labelText) {
      super();

      labelName.setText(labelText);
      labelName.setMaxWidth(Double.MAX_VALUE);
      labelPath.setMaxWidth(0);
      labelPath.setText("Path");

      pbProgress.setMaxWidth(Double.MAX_VALUE);

      HBox.setHgrow(labelName, Priority.ALWAYS);
      HBox.setHgrow(pbProgress, Priority.ALWAYS);

      HBox.setMargin(labelName, new Insets(5, 0, 0, 0));
      HBox.setMargin(pbProgress, new Insets(0, 0, 0, 0));

      labelPath.setVisible(false);

      buttonSpacer.setPrefSize(prefWidth, prefHeight);

      labelElapse.setPrefSize(50, prefHeight);
      labelElapse.setText("Time");;

      progressBarSpacer.setPrefSize(prefWidth * 6, prefHeight);

      filePlay = new File("src/image/play.png");
      fileStop = new File("src/image/stop.png");

      Image imagePlay = new Image(filePlay.toURI().toString());
      Image imageStop = new Image(fileStop.toURI().toString());

      ivPlay.setImage(imagePlay);
      ivStop.setImage(imageStop);

      ivPlay.setFitHeight(prefHeight);
      ivPlay.setFitWidth(prefWidth);
      ivStop.setFitHeight(prefHeight);
      ivStop.setFitWidth(prefWidth);

      buttonPlayPause.setGraphic(ivPlay);
      buttonStop.setGraphic(ivStop);

      buttonPlayPause.setMaxSize(prefWidth, prefHeight);
      buttonStop.setMaxSize(prefWidth, prefHeight);

      pbProgress.setMaxHeight(2);
      pbProgress.setPrefHeight(2);

      hbDetail.getChildren().addAll(buttonPlayPause, buttonStop, buttonSpacer, labelName, labelPath);
      hbProgress.getChildren().addAll(progressBarSpacer, pbProgress, labelElapse);
      this.getChildren().addAll(hbDetail, hbProgress);
    }

  }

  public Parent createContent() {
    BorderPane layout = new BorderPane();

    List < lvCell > list = new ArrayList < > ();
    for (int i = 0; i < 10; i++) {
      list.add(new lvCell("Item " + i));
    }

    ListView < lvCell > listView = new ListView < lvCell > ();
    ObservableList < lvCell > myObservableList = FXCollections.observableList(list);
    listView.setItems(myObservableList);

    layout.setCenter(listView);

    return layout;
  }

  @Override
  public void start(Stage stage) throws Exception {
    stage.setScene(new Scene(createContent()));
    stage.setWidth(300);
    stage.setHeight(200);
    stage.show();
  }

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

The screen looks like this:

reulting screen

Any help will be greatly appreciated.

Thanks in advance, and wishing you a peaceful journey.

Yas

Upvotes: 1

Views: 1323

Answers (1)

fabian
fabian

Reputation: 82461

This is not a class well designed to put into a ListView. An object used as item in a ListView should contain data; the ListCell implementation produced by the cellFactory is responsible for determining the visual representation of the data in the ListView. This way you avoid the creation of nodes for every object reducing the memory footprint, which is exactly what ListView is designed for.

Simplified example

The data here contains just the progress and some text; it's displayed in a ProgressBar and the text of the cell; an additional button in the cell allows increasing the progress by 0.25 for each click and removing any items reaching a progress of 1.

Data class

public class Data {

    private final DoubleProperty progress = new SimpleDoubleProperty();

    private final String text;

    public Data(String text) {
        this.text = text;
    }

    public double getProgress() {
        return progress.get();
    }

    public void setProgress(double value) {
        progress.set(value);
    }

    public String getText() {
        return text;
    }

    public ObservableValue<? extends Number> progressProperty() {
        return progress;
    }

}

ListView code

ListView<Data> listView = new ListView<>(someData);
listView.setCellFactory(l -> new ListCell<Data>() {

    private final ProgressBar progressBar = new ProgressBar();
    private final Button button = new Button("increase");
    private final HBox content = new HBox(progressBar, button);

    {
        button.setOnAction(evt -> {
            Data item = getItem();
            int index = getIndex();
            double progress = item.getProgress() + 0.25;
            item.setProgress(progress);
            if (progress >= 1) {
                getListView().getItems().remove(index);
            }
        });
    }

    @Override
    protected void updateItem(Data item, boolean empty) {
        super.updateItem(item, empty);
        progressBar.progressProperty().unbind();

        if (item == null) {
            setGraphic(null);
            setText("");
        } else {
            setGraphic(content);
            setText(item.getText());
            progressBar.progressProperty().bind(item.progressProperty());
        }
    } 

});

Upvotes: 2

Related Questions