使用JavaFX滚动XYChart [英] Scrolling XYChart with JavaFX

查看:186
本文介绍了使用JavaFX滚动XYChart的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现类似于Windows中的网络使用图。我显示了最后30秒的数据,新值出现在右侧并向左移动。

I'm trying to implement a network usage graph similar to the one in Windows. I'm showing the last 30 seconds worth of data with new values appearing at the right hand side and moving to the left.

我已经完成了所有工作我不能让垂直网格线随数据移动。相反,主刻度线总是保持静止,而图中的线只是移动。

I've got it all working apart from I cannot get the vertical grid lines to move with the data. Instead the major ticks always stay static and the just the line on the graph moves.

即。在下图中,我预计主要价位将保持在5的tickUnit,并显示在55和60. 65处的标签将在屏幕外。

i.e. in the image below I'm expecting the major ticks to stay at the tickUnit of 5 and be shown at 55 and 60. The label at 65 would be off the screen.


  • 我已禁用autoRanging,我手动更新了轴上的lowerBound和upperBound属性。

  • 启用autoRanging后,您将获得样式效果,其中线向yAxis移动几秒钟,然后跳过主要的刻度距离,依此类推。

  • 我也尝试在图表和轴上启用动画属性。

  • I've disabled autoRanging and I'm manually updating lowerBound and upperBound properties on the axis.
  • With autoRanging enabled you get a snake style effect where the line moves towards the yAxis for a few seconds and then jumps by a major tick distance, and so on.
  • I've also tried enabling the animation property on both the chart and the axis.

我的任何解决方案/解决方案都建立在已有的基础之上,而不是从头开始编写。是否可以通过子类化来自定义行为?

I'm after any solution / workaround that builds upon what's already there rather than having to write from scratch. Is it possible to customize the behaviour by subclassing?

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class StackOverflow25383566 extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        final NumberAxis xAxis = new NumberAxis();
        xAxis.setAutoRanging(false);
        xAxis.setForceZeroInRange(false);
        xAxis.setTickUnit(5);

        final NumberAxis yAxis = new NumberAxis(0, 15, 1);
        yAxis.setAutoRanging(false);

        final LineChart<Number, Number> chart = new LineChart<Number, Number>(
                xAxis, yAxis);
        chart.setAnimated(false);
        chart.setCreateSymbols(false);
        chart.setLegendVisible(false);
        final XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
        chart.getData().add(series);
        series.getData().addListener(
                new ListChangeListener<Data<Number, Number>>() {

                    @Override
                    public void onChanged(
                            ListChangeListener.Change<? extends Data<Number, Number>> arg0) {
                        ObservableList<Data<Number, Number>> data = series
                                .getData();
                        xAxis.setLowerBound(data.get(0).getXValue()
                                .doubleValue());
                        xAxis.setUpperBound(data.get(data.size() - 1)
                                .getXValue().doubleValue());
                    }

                });
        stage.setScene(new Scene(new BorderPane(chart), 800, 600));
        stage.show();

        final Runnable update = new Runnable() {
            private int clock;

            @Override
            public void run() {
                try {
                    ObservableList<Data<Number, Number>> data = series
                            .getData();
                    if (data.size() > 10) {
                        data.remove(0);
                    }
                    data.add(new XYChart.Data<Number, Number>(clock, clock % 13));
                    clock++;
                } catch (Throwable e) {
                    // executors silently swallow exceptions
                    e.printStackTrace();
                    throw e;
                }
            }

        };
        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
                new Runnable() {

                    @Override
                    public void run() {
                        Platform.runLater(update);
                    }

                }, 0, 500, TimeUnit.MILLISECONDS);
    }

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


推荐答案

我能够通过继承ValueAxis来解决这个问题,以便它返回始终是tickUnit倍数的tick标记。

I was able to solve this by subclassing ValueAxis so that it returns tick markers that are always multiples of tickUnit.


  • 自开发此解决方案以来,我已经意识到 jfxutils ,其中包含一个名为 StableTickAxis ,但其JavaDoc声明未准备好使用

  • Since developing this solution, I've been made aware of jfxutils which contains a class called StableTickAxis, however its JavaDoc states "Not ready to be used"

此图片显示了什么我之后,即不一定以主要的勾号开始。

This picture shows what I was after, i.e. not necessarily starting with a major tick.

private class SpecialAxis extends ValueAxis<Number> {
    private SimpleObjectProperty<Double> tickUnitProperty = new SimpleObjectProperty<Double>(
            5d);

    @Override
    protected List<Number> calculateMinorTickMarks() {
        List<Number> ticks = new ArrayList<Number>();
        double tickUnit = tickUnitProperty.get() / getMinorTickCount();
        double start = Math.floor(getLowerBound() / tickUnit) * tickUnit;
        for (double value = start; value < getUpperBound(); value += tickUnit) {
            ticks.add(value);
        }
        return ticks;
    }

    @Override
    protected List<Number> calculateTickValues(double arg0, Object arg1) {
        List<Number> ticks = new ArrayList<Number>();
        double tickUnit = tickUnitProperty.get();
        double start = Math.floor(getLowerBound() / tickUnit) * tickUnit;
        for (double value = start; value < getUpperBound(); value += tickUnit) {
            ticks.add(value);
        }
        return ticks;
    }

    @Override
    protected Object getRange() {
        // not sure how this is used??
        return null;
    }

    @Override
    protected String getTickMarkLabel(Number label) {
        return label.toString();
    }

    @Override
    protected void setRange(Object range, boolean arg1) {
        // not sure how this is used??
    }

    public SimpleObjectProperty<Double> getTickUnitProperty() {
        return tickUnitProperty;
    }

    public void setTickUnit(double tickUnit) {
        tickUnitProperty.set(tickUnit);
    }

}

这篇关于使用JavaFX滚动XYChart的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆