如何获取BarChart(JavaFx)中单击的柱形图的值?

问题描述 投票:0回答:1

我需要在单击 JavaFX BarChart 中的条形图时获取该条形的 X 和 Y 轴值,以便处理和保存此数据。使用 MVC 架构,我必须将包含 BarChart 的视图与存在 BarChart 条形事件处理程序的控制器分开。因此,我无法获取单击栏的 x 或 y 值,因为一旦进入处理程序,我就无法再检索单击栏。我看到有些人在监听器附加到栏的 for 循环中获取数据值,并使用它,但显然,这不会返回单击的栏,而是返回监听器附加的最后一个栏。那么,一旦我进入控制器的事件处理程序,如何检索单击的栏?控制器和视图代码如下。

控制器:

EventHandler<MouseEvent> statsBarButtonHandler = new EventHandler<>() {
            @Override
            public void handle(MouseEvent actionEvent) {
                System.out.println("PASSO AI GENERI E ARTISTI");
                StatisticsHandler statDomain = new StatisticsHandler();
              
                mainStage.setScene(genreView);
            }
        };

        for (XYChart.Data<Number, String> data : typeView.getTypeSerie().getData()) {
            data.getNode().setOnMouseClicked(statsBarButtonHandler);
            this.dataClicked = data;
        }

条形图:

BarChart <Number, String> barChart = new BarChart<>(xAxis, yAxis);
XYChart.Series<Number, String> series = new XYChart.Series<>();
        this.typeSerie=series;

        // 
        series.getData().add(new XYChart.Data<>(0, "Category 1"));
        series.getData().add(new XYChart.Data<>(14, "Category 2"));
        series.getData().add(new XYChart.Data<>(72, "Category 3"));
        series.getData().add(new XYChart.Data<>(55, "Category 4"));
        series.getData().add(new XYChart.Data<>(100, "Category 5"));

        // Aggiunta della serie al grafico
        barChart.getData().add(series);

请记住,必须使用 MVC 架构,我不能将控制器放在视图中;他们必须保持分开。所以我需要找到一种方法来直接在控制器的处理程序中获取值。

正如我已经提到的,我尝试了在某些网站上找到的方法,从附加侦听器的 for 循环中获取单击的栏,如此处所示,但作为输出,我总是获得最后一个关联的类别,即 5,并且不是点击的那个。

private XYChart.Data dataClicked;


EventHandler<MouseEvent> statsBarButtonHandler = new EventHandler<>() {
            @Override
            public void handle(MouseEvent actionEvent) {
                System.out.println("PASSO AI GENERI E ARTISTI");
                StatisticsHandler statDominio = new StatisticsHandler();

                System.out.println(dataClicked.getYValue());
                
            }
        };

        for (XYChart.Data<Number, String> data : typeView.getTypeSerie().getData()) {
            data.getNode().setOnMouseClicked(statsBarButtonHandler);
            this.dataClicked = data;
        }
java javafx model-view-controller bar-chart handler
1个回答
0
投票

在我看来(和 James_D 的),最好的解决方案是为每个数据的节点注册一个唯一的

EventHandler
。这将使您知道单击了哪个数据的节点,因为只有一个这样的节点可以触发处理程序。下面显示了这方面的示例,但不是在 MVC 的上下文中。

import java.util.List;
import java.util.Random;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;

public class Main extends Application {

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

  @Override
  public void start(Stage primaryStage) {
    var xAxis = new NumberAxis();
    xAxis.setLabel("X");

    var yAxis = createCategoryAxis();

    var chart = new BarChart<>(xAxis, yAxis);
    chart.getData().add(createSeries(yAxis.getCategories()));

    primaryStage.setScene(new Scene(chart, 600, 400));
    primaryStage.show();
  }

  private CategoryAxis createCategoryAxis() {
    var yAxis = new CategoryAxis();
    yAxis.setLabel("Y");
    for (int i = 1; i <= 5; i++) {
      yAxis.getCategories().add("Category " + i);
    }
    return yAxis;
  }

  private XYChart.Series<Number, String> createSeries(List<String> categories) {
    var random = new Random();

    var series = new XYChart.Series<Number, String>();
    series.setName("Series");
    for (var category : categories) {
      var data = new XYChart.Data<Number, String>(random.nextInt(1, 20), category);
      // Note 'subscribe' was added in JavaFX 21. If using an older version you can do
      // something similar with a ChangeListener (though note the Consumer passed to
      // 'subscribe' will be notified of the current value immediately, a ChangeListener
      // will not).
      data.nodeProperty().subscribe((oldNode, newNode) -> {
        // Stop listening to the old node to prevent potential memory leaks.
        if (oldNode != null) oldNode.setOnMouseClicked(null);
        if (newNode != null) {
          // Unique EventHandler for each XYChart.Data instance. This makes it easy to know
          // which XYChart.Data's node was clicked, since the instance is captured.
          newNode.setOnMouseClicked(e -> {
            e.consume();
            var x = data.getXValue();
            var y = data.getYValue();
            System.out.printf("Data node clicked: '%s' = %d%n", y, x);
          });
        }
      });
      series.getData().add(data);
    }
    return series;
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.