首页 > 解决方案 > 在实时 javafx 条形图的每个顶部添加值

问题描述

我是 Java 新手,我正在尝试创建一个实时 javaFX 条形图,它显示每个条形顶部的更新值。我得到了这个每秒更新的条形图。如何使用此图表在每个条形顶部添加值。网上还有其他例子,但与此代码上的实时条形图不兼容。我怎样才能在每个栏中添加文本。谢谢

import java.util.Calendar;
import java.util.TimeZone;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;
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 App extends Application {
    private ScheduledExecutorService scheduledExecutorService;

    final static String austria = "Austria";
    final static String brazil = "Brazil";
    final static String france = "France";

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Realtime Bar Chart Demo");

        //defining the axes
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();

        xAxis.setAnimated(false);
        yAxis.setAnimated(false);

        //creating the bar chart with two axis
        final BarChart<String,Number> bc =  new BarChart<>(xAxis,yAxis);
        bc.setAnimated(false);
        bc.setTitle("Country Summary");
        xAxis.setLabel("Country");
        yAxis.setLabel("Value");

        //defining a series to display data
        XYChart.Series<String, Number> seriesA = new XYChart.Series<>();
        seriesA.setName("Austra");

        XYChart.Series<String, Number> seriesB = new XYChart.Series<>();
        seriesB.setName("Brazil");

        XYChart.Series<String, Number> seriesC = new XYChart.Series<>();
        seriesC.setName("France");

        // add series to chart
        bc.getData().add(seriesA);
        bc.getData().add(seriesB);
        bc.getData().add(seriesC);

        // setup scene
        Scene scene = new Scene(bc, 800, 600);
        primaryStage.setScene(scene);

        // show the stage
        primaryStage.show();

        // setup a scheduled executor to periodically put data into the chart
        scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

        // input data onto graph per second
        scheduledExecutorService.scheduleAtFixedRate(() -> {

            Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
            int secondA = cal.get(Calendar.SECOND);
            int secondB = secondA + 27;
            int secondC = secondA + 14;

            // Update the chart
            Platform.runLater(() -> {
                // input realtime data number
                seriesA.getData().add(new XYChart.Data<>(austria, secondA));
                seriesB.getData().add(new XYChart.Data<>(brazil, secondB));
                seriesC.getData().add(new XYChart.Data<>(france, secondC));
            });
        }, 0, 1, TimeUnit.SECONDS);
    }

    @Override
    public void stop() throws Exception {
        super.stop();
        scheduledExecutorService.shutdownNow();
    }
}

标签: javajavafxcharts

解决方案


以下是在您的代码中实施一些更改并使用此答案中提出的解决方案的mre :

import java.util.Calendar;
import java.util.TimeZone;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Node;
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.scene.chart.XYChart.Data;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class App extends Application {
    private ScheduledExecutorService scheduledExecutorService;

    final static String austria = "Austria",  brazil = "Brazil",  france = "France";
    private IntegerProperty secondA,  secondB , secondC; 
    private Text secondAText, secondBText , secondCText;

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Realtime Bar Chart Demo");

        //defining the axes
        final CategoryAxis xAxis = new CategoryAxis();
        final NumberAxis yAxis = new NumberAxis();

        xAxis.setAnimated(false);
        yAxis.setAnimated(false);

        //creating the bar chart with two axis
        final BarChart<String,Number> bc =  new BarChart<>(xAxis,yAxis);
        bc.setAnimated(false);
        bc.setTitle("Country Summary");
        xAxis.setLabel("Country");
        yAxis.setLabel("Value");

        //defining a series to display data
        XYChart.Series<String, Number> seriesA = new XYChart.Series<>();
        Data<String, Number> dataA = new XYChart.Data<>(austria,0);
        seriesA.getData().add(dataA);
        seriesA.setName("Austra");

        secondA = new SimpleIntegerProperty(0);
        secondAText = new Text("");
        secondA.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {
            dataA.setYValue(newValue);
            secondAText.setText(String.valueOf(newValue));
        });

        XYChart.Series<String, Number> seriesB = new XYChart.Series<>();
        Data<String, Number> dataB = new XYChart.Data<>(brazil,0);
        seriesB.getData().add(dataB);
        seriesB.setName("Brazil");
        secondB =  new SimpleIntegerProperty(0);
        secondB.bind(secondA.add(27));
        secondBText = new Text("");
        secondB.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {
            dataB.setYValue(newValue);
            secondBText.setText(String.valueOf(newValue));
        });

        XYChart.Series<String, Number> seriesC = new XYChart.Series<>();
        Data<String, Number> dataC = new XYChart.Data<>(france,0);
        seriesC.getData().add(dataC);
        seriesC.setName("France");

        secondC =  new SimpleIntegerProperty(0);
        secondC.bind(secondA.add(14));
        secondCText = new Text("");
        secondC.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {
            dataC.setYValue(newValue);
            secondCText.setText(String.valueOf(newValue));
        });

        // add series to chart
        bc.getData().add(seriesA);
        bc.getData().add(seriesB);
        bc.getData().add(seriesC);

        displayLabelForData(dataA, secondAText);
        displayLabelForData(dataB, secondBText);
        displayLabelForData(dataC, secondCText);

        // setup scene
        Scene scene = new Scene(bc, 800, 600);
        primaryStage.setScene(scene);

        // show the stage
        primaryStage.show();

        // setup a scheduled executor to periodically put data into the chart
        scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

        // input data onto graph per second
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

            // Update the chart
            Platform.runLater(() -> {
                secondA.set( cal.get(Calendar.SECOND));
            });
        }, 0, 1, TimeUnit.SECONDS);
    }

    @Override
    public void stop() throws Exception {
        super.stop();
        scheduledExecutorService.shutdownNow();
    }

    private void displayLabelForData(XYChart.Data<String, Number> data, Text text) {

        final Node node = data.getNode();
        ((Group) node.getParent()).getChildren().add(text);

        node.boundsInParentProperty().addListener((ChangeListener<Bounds>) (ov, oldBounds, bounds) -> {
            text.setLayoutX(
                    Math.round( bounds.getMinX() + bounds.getWidth() / 2 - text.prefWidth(-1) / 2));
            text.setLayoutY(Math.round( bounds.getMinY() - text.prefHeight(-1) * 0.5));
        });
    }
}

旁注:您可以使用 javafx 工具来运行定期任务:

    Timeline timeline = new Timeline(new KeyFrame(
            Duration.seconds(1),
            e -> {
                Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
                secondA.set( cal.get(Calendar.SECOND));
            }
     ));
    timeline.setCycleCount(Animation.INDEFINITE);
    timeline.play();

在此处输入图像描述


推荐阅读