You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX 8中如何在LineChart的X轴绘制LocalTime并升序排序?

问题解答:在JavaFX LineChart的X轴使用LocalTime并实现升序排列

错误原因

你遇到的CategoryAxis.toNumericValue错误,本质是因为LineChart的X轴默认使用了CategoryAxis,该轴仅支持字符串类型的分类值。当传入LocalTime类型数据时,轴无法完成类型转换,导致图表无法渲染数据。

解决方案

要在X轴使用LocalTime并实现动态添加后自动升序,有两种可行方案:

方案1:使用NumberAxis并转换LocalTime为数值

将LocalTime转换为从午夜开始的毫秒数(或秒数)作为数值传入NumberAxis,再通过自定义轴标签格式化器将数值转回LocalTime显示。

代码示例:

  1. 调整FXML中的轴定义:
<LineChart fx:id="chart">
    <xAxis>
        <NumberAxis fx:id="xAxis" label="时间"/>
    </xAxis>
    <yAxis>
        <NumberAxis label="数值"/>
    </yAxis>
</LineChart>
  1. 代码中处理数据转换与轴格式化:
@FXML
private LineChart<Number, Number> chart;
@FXML
private NumberAxis xAxis;

// 初始化时设置轴标签格式化器
xAxis.setTickLabelFormatter(new StringConverter<Number>() {
    @Override
    public String toString(Number value) {
        // 将毫秒数转换为LocalTime
        long millis = value.longValue();
        return LocalTime.ofNanoOfDay(millis * 1_000_000).toString();
    }

    @Override
    public Number fromString(String string) {
        // 反向转换(可选,支持用户输入时使用)
        return LocalTime.parse(string).toNanoOfDay() / 1_000_000;
    }
});

// 添加数据时转换LocalTime为毫秒数
XYChart.Series<Number, Number> series = new XYChart.Series<>();
chart.getData().add(series);

LocalTime time = LocalTime.parse("11:05:45.207");
long millisSinceMidnight = time.toNanoOfDay() / 1_000_000;
series.getData().add(new XYChart.Data<>(millisSinceMidnight, 5));

// 动态添加新数据,图表自动按数值升序排列
LocalTime newTime = LocalTime.parse("11:06:00.000");
long newMillis = newTime.toNanoOfDay() / 1_000_000;
series.getData().add(new XYChart.Data<>(newMillis, 8));

方案2:自定义LocalTimeAxis(推荐)

创建继承自ValueAxis<LocalTime>的自定义轴,直接支持LocalTime类型,无需手动转换数值。

自定义LocalTimeAxis代码:

public class LocalTimeAxis extends ValueAxis<LocalTime> {
    private final LocalTime minTime = LocalTime.MIN;
    private final LocalTime maxTime = LocalTime.MAX;

    @Override
    protected List<LocalTime> calculateTickValues(double length, Object range) {
        // 按小时生成刻度(可根据需求调整)
        List<LocalTime> ticks = new ArrayList<>();
        for (int hour = 0; hour < 24; hour++) {
            ticks.add(LocalTime.of(hour, 0));
        }
        return ticks;
    }

    @Override
    protected Object getRange() {
        return new Range<>(minTime, maxTime);
    }

    @Override
    protected double toNumericValue(LocalTime time) {
        // 将LocalTime转换为0-1的比例值
        return time.toNanoOfDay() / (double) LocalTime.MAX.toNanoOfDay();
    }

    @Override
    protected LocalTime toRealValue(double value) {
        // 将比例值转回LocalTime
        long nano = (long) (value * LocalTime.MAX.toNanoOfDay());
        return LocalTime.ofNanoOfDay(nano);
    }

    @Override
    protected void setRange(Object range, boolean animate) {
        // 自定义范围逻辑(可选)
    }
}

使用自定义轴:

  1. FXML中引用自定义轴:
<LineChart fx:id="chart">
    <xAxis>
        <localTimeAxis.LocalTimeAxis label="时间"/>
    </xAxis>
    <yAxis>
        <NumberAxis label="数值"/>
    </yAxis>
</LineChart>
  1. 代码中直接使用LocalTime:
@FXML
private LineChart<LocalTime, Number> chart;

// 添加数据
XYChart.Series<LocalTime, Number> series = new XYChart.Series<>();
chart.getData().add(series);
series.getData().add(new XYChart.Data<>(LocalTime.parse("11:05:45.207"), 5));
series.getData().add(new XYChart.Data<>(LocalTime.parse("11:04:00.000"), 3)); // 自动升序排列

// 动态添加新数据
series.getData().add(new XYChart.Data<>(LocalTime.parse("11:06:30.000"), 7));

额外注意事项

  • 避免原始类型:你的Observer.addChart方法使用了原始LineChart类型,会导致类型擦除问题,建议改为泛型方法:
public void addChart(LineChart<LocalTime, Number> chart) {
    this.chart = chart;
}

内容的提问来源于stack exchange,提问作者Michael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 18:22:37