Javafx StackedBarChart错误

时间:2015-09-02 14:02:21

标签: java charts javafx

我正在使用StackedBarChart开发应用程序,但我发现了我认为是一个小错误,如果图表的动画属性设置为false,则不会呈现负值。尝试下面的代码进行测试,任何人都知道如何解决它?

提前致谢。

import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.StackedBarChart;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * Created by fabiofrumento on 28/04/15.
 */
public class Scratch extends Application {

    private static final SimpleDateFormat ONESECOND_CHART_DATE_FORMAT = new SimpleDateFormat("HH:mm:ss",
                                                                                             Locale.ENGLISH);
    private boolean stopThreads;

    CategoryAxis xAxisActive   = new CategoryAxis();
    CategoryAxis xAxisReactive = new CategoryAxis();
    NumberAxis   yAxisActive   = new NumberAxis();
    NumberAxis   yAxisReactive = new NumberAxis();

    {
        xAxisActive.setLabel("Time");
        xAxisReactive.setLabel("Time");
        yAxisActive.setLabel("animated = false");
        yAxisReactive.setLabel("animated = true");
    }

    private StackedBarChart<String, Number> onesecondActiveBarChart         = new StackedBarChart<String, Number>(xAxisActive,
                                                                                                                  yAxisActive);
    private StackedBarChart<String, Number> onesecondReactiveBarChart       = new StackedBarChart<String, Number>(xAxisReactive,
                                                                                                                  yAxisReactive);
    private XYChart.Series<String, Number>  onesecondActiveConsumedSerie    = new XYChart.Series<>();
    private XYChart.Series<String, Number>  onesecondActiveGeneratedSerie   = new XYChart.Series<>();
    private XYChart.Series<String, Number>  onesecondReactiveConsumedSerie  = new XYChart.Series<>();
    private XYChart.Series<String, Number>  onesecondReactiveGeneratedSerie = new XYChart.Series<>();

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

    @Override
    public void start(Stage primaryStage) throws
                                          Exception {
        VBox root = new VBox();

        initCharts();

        root.getChildren()
            .addAll(onesecondActiveBarChart,
                    onesecondReactiveBarChart);
        Scene scene = new Scene(root,
                                1024,
                                768);

        primaryStage.setTitle("JecomoduleUI");
        primaryStage.setScene(scene);
        primaryStage.setFullScreen(true);
        primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent event) {
                stopThreads = true;
            }
        });

        primaryStage.show();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!stopThreads) {
                    try {
                        Thread.sleep(1000);
                        Platform.runLater(new Runnable() {
                            @Override
                            public void run() {
                                updateActiveData();
                            }
                        });
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

    }

    private void initCharts() {
        onesecondActiveConsumedSerie.setName("Cons. W");
        onesecondActiveGeneratedSerie.setName("Gen. W");
        onesecondReactiveConsumedSerie.setName("Cons. VAR");
        onesecondReactiveGeneratedSerie.setName("Gen.. VAR");
        onesecondActiveBarChart.getData()
                               .addAll(onesecondActiveConsumedSerie,
                                       onesecondActiveGeneratedSerie);
        onesecondActiveBarChart.setAnimated(false);
        onesecondReactiveBarChart.getData()
                                 .addAll(onesecondReactiveConsumedSerie,
                                         onesecondReactiveGeneratedSerie);
    }

    void updateActiveData() {
        Date    format = new Date();
        Integer oneSecondActiveConsumedValue;
        Integer oneSecondActiveGeneratedValue;
        Double  rand   = Math.random();
        Integer rnd    = new Double(1000l + rand * 9000l).intValue();
        if (rnd % 2 == 0) {
            oneSecondActiveConsumedValue = rnd;
            oneSecondActiveGeneratedValue = 0;
        } else {
            oneSecondActiveConsumedValue = 0;
            oneSecondActiveGeneratedValue = 0 - rnd;
        }
        onesecondActiveConsumedSerie.getData()
                                    .add(new XYChart.Data<String, Number>(ONESECOND_CHART_DATE_FORMAT.format(format),
                                                                          oneSecondActiveConsumedValue));
        if (onesecondActiveConsumedSerie.getData()
                                        .size() > 10)
            onesecondActiveConsumedSerie.getData()
                                        .remove(0);
        onesecondActiveGeneratedSerie.getData()
                                     .add(new XYChart.Data<String, Number>(ONESECOND_CHART_DATE_FORMAT.format(format),
                                                                           oneSecondActiveGeneratedValue));
        if (onesecondActiveGeneratedSerie.getData()
                                         .size() > 10)
            onesecondActiveGeneratedSerie.getData()
                                         .remove(0);

        onesecondReactiveConsumedSerie.getData()
                                      .add(new XYChart.Data<String, Number>(ONESECOND_CHART_DATE_FORMAT.format(format),
                                                                            oneSecondActiveConsumedValue));
        if (onesecondReactiveConsumedSerie.getData()
                                          .size() > 10)
            onesecondReactiveConsumedSerie.getData()
                                          .remove(0);
        onesecondReactiveGeneratedSerie.getData()
                                       .add(new XYChart.Data<String, Number>(ONESECOND_CHART_DATE_FORMAT.format(format),
                                                                             oneSecondActiveGeneratedValue));
        if (onesecondReactiveGeneratedSerie.getData()
                                           .size() > 10)
            onesecondReactiveGeneratedSerie.getData()
                                           .remove(0);
    }

}

1 个答案:

答案 0 :(得分:3)

是的,这似乎是一个JavaFX错误(Java 8u60)。

查看StackedBarChart的源代码,只有在项目节点的样式类中找到“否定”时才能正确绘制具有负值的项目(请参阅StackedBarChart#layoutPlotChildren)。

“负面”样式应由StackedBarChart#dataItemAdded设置。对于动画图表StackedBarChart#animateData被调用,如果项目的值为负,则将“否定”样式添加到节点。

对于非动画数据,该节点会添加到聊天的绘图子节点而不更新样式类。

作为解决方法,覆盖onesecondActiveBarChart的dataItemAdded

private StackedBarChart<String, Number> onesecondActiveBarChart = new StackedBarChart<String, Number>(xAxisActive, yAxisActive) {
    @Override
    protected void dataItemAdded(XYChart.Series<String,Number> series, int itemIndex, XYChart.Data<String,Number> item) {
        super.dataItemAdded(series, itemIndex, item);

        Node bar = item.getNode();
        double barVal = item.getYValue().doubleValue();

        if (barVal < 0) {
            bar.getStyleClass().add("negative");
        }   
    }       
};