JavaFX图表轴标签格式

JavaFX图表轴标签格式,java,charts,javafx,label,linechart,Java,Charts,Javafx,Label,Linechart,我写了一个简单的程序来监控我的ping。我目前正在使用带有自动测距功能的NumberAxis,每次ping后,我在末尾添加新数据,删除第一个数据,并为X轴位置增加totalCount变量 我希望X轴标签: 显示自启动以来经过的时间。因此,例如,以0.25s ping间隔进行第1100次ping的标签应为4m 35s 显示自ping以来的时间。这将要求标签保持静态(不随绘图移动)并按相反顺序排列 这两个(最好是第一个)中的任何一个都可以实现吗?我想我必须使用CategoryAxis来实现这一点

我写了一个简单的程序来监控我的ping。我目前正在使用带有自动测距功能的
NumberAxis
,每次ping后,我在末尾添加新数据,删除第一个数据,并为X轴位置增加
totalCount
变量

我希望X轴标签:

  • 显示自启动以来经过的时间。因此,例如,以0.25s ping间隔进行第1100次ping的标签应为
    4m 35s
  • 显示自ping以来的时间。这将要求标签保持静态(不随绘图移动)并按相反顺序排列
这两个(最好是第一个)中的任何一个都可以实现吗?我想我必须使用
CategoryAxis
来实现这一点,但我不确定如何创建无限数量的类别并选择只显示完整的分钟数。是否可以保留
NumberAxis
,以便更方便地使用传入数据,并只更改标签文本格式?我已经有了一种将秒转换为
00h 00m 00s
格式的方法

还有一件事,我认为与自动范围相关,图表不会在每次输入后刷新,但只有在超过给定范围的10%时才会刷新。因此,对于图中的1000范围,它将绘制100个新ping,然后将所有内容向左移动100个位置。我能不能改变它,让它在1点后移动

不确定是否相关,但我会发布代码:

控制器

public class GuiController implements Initializable {

@FXML
Button startButton, stopButton;
@FXML
TextField sField, nField, ipField;
@FXML
LineChart<Integer, Integer> chart;
@FXML
Label timeLabel, pingLabel;

ScheduledService<Integer> scheduler;
ObservableList<Data<Integer, Integer>> data;
public static int totalCount = 0;

private String getTime(double seconds) {
    int h = (int) (seconds / 3600);
    int m = (int) ((seconds % 3600) / 60);
    int s = (int) (seconds % 60);
    return String.format("%dh %dm %ds", h, m, s);
}

public void start() {
    if (sField.getText().isEmpty() || Double.parseDouble(sField.getText()) == 0)
        sField.setText("0.1");
    data = FXCollections.observableArrayList();
    int size = Integer.parseInt(nField.getText());
    stop = false;
    flip();
    XYChart.Series<Integer, Integer> series = new Series<>();
    for (int i = 0; i < size; i++) {
        series.getData().add(new XYChart.Data<Integer, Integer>(totalCount++, 0));
    }
    chart.getData().clear();
    chart.getData().add(series);
    scheduler.setPeriod(Duration.seconds(Double.parseDouble(sField.getText())));
    scheduler.setOnSucceeded(new EventHandler<WorkerStateEvent>() {

        @Override
        public void handle(WorkerStateEvent event) {
            if (series.getData().size() >= size)
                series.getData().remove(0);
            series.getData().add(new XYChart.Data<>(totalCount++, scheduler.getValue()));
            updatePingLabel(scheduler.getValue());
        }
    });
    scheduler.restart();
}

public void stop() {
    scheduler.cancel();
    stop = true;
    flip();
    totalCount = 0;
}

public static boolean isNumeric(String str) {
    return str.matches("?\\d+(\\.\\d+)?");
}

public void flip() {
    ipField.setDisable(!ipField.isDisabled());
    nField.setDisable(!nField.isDisabled());
    sField.setDisable(!sField.isDisabled());
    startButton.setDisable(!startButton.isDisabled());
    stopButton.setDisable(!stopButton.isDisabled());
}

public void updatePingLabel(int ping) {
    pingLabel.setText(ping + "ms");
    if (ping < 80)
        pingLabel.setTextFill(Color.LAWNGREEN);
    if (ping >= 80 && ping < 150)
        pingLabel.setTextFill(Color.GOLD);
    if (ping >=150 && ping < 400)
        pingLabel.setTextFill(Color.ORANGE);
    if (ping >= 400)
        pingLabel.setTextFill(Color.RED);
}


@Override
public void initialize(URL arg0, ResourceBundle arg1) {
    chart.getXAxis().setVisible(false);
    chart.getXAxis().setAutoRanging(true);
    stopButton.setDisable(true);
    chart.getYAxis().setAutoRanging(true);
    sField.textProperty().addListener(new ParamsChangeListener());
    nField.textProperty().addListener(new ParamsChangeListener());
    scheduler = new ScheduledService<Integer>() {
        @Override
        protected Task<Integer> createTask() {
            return new PingTask(ipField.getText());
        }
    };
}

class ParamsChangeListener implements ChangeListener<String> {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue,
            String newValue) {
        if (isNumeric(newValue))
            timeLabel.setText(getTime(Double.parseDouble(sField.getText())
                    * Integer.parseInt(nField.getText())));
    }
}
}
start()
方法中

    ((ValueAxis<Integer>) chart.getXAxis()).setTickLabelFormatter(new XAxisLabelConverter(
            Double.parseDouble(sField.getText()),size));
((ValueAxis)chart.getXAxis()).setTickLabelFormatter(新的XaxLabelConverter(
parseDouble(sField.getText()),size));
您可以添加一个

您可能只想删除x轴。它实际上没有添加任何信息。如果你只是显示最后100次的ping,相隔0.25秒,那么你不需要一个轴来知道它们是什么时候发生的

由于轴的范围,图表仅在100次ping后移动。间隔将取决于总范围。改变这一点的唯一方法是关闭自动测距并自行设置最大、最小和大小。你可以用这个

如果你想格式化,你需要一个专门的转换器,因为你需要修改数字。图表需要将数字转换为字符串,因此使用
StringConverter
,例如

    xAxis.setTickLabelFormatter(new StringConverter<Number>() {
        @Override
        public String toString(Number object) {
            return (object.intValue() * 0.25) + "s";
        }

        @Override
        public Number fromString(String string) {
            return 0;
        }
    });
xAxis.setTickLabelFormatter(新的StringConverter(){
@凌驾
公共字符串toString(数字对象){
返回值(object.intValue()*0.25)+“s”;
}
@凌驾
公共编号fromString(String){
返回0;
}
});
另外,我只在windows上使用过这个,但你可以看到它是否比新进程性能更好


要收敛到MCVE,您还可以发布fxml。@UlukBiy添加了fxml。您一直试图更改NumberAxis的定义。声明是
公共最终类编号axis扩展了ValueAxis
。我不是类型方面的专家,但我认为最好只使用Number并获取intValue()。您的类型完全混乱了。由于您的FXML正在创建
NumberAxis
实例作为轴,并且
NumberAxis扩展值Axis扩展轴
,因此您必须使图表成为
折线图
。然后需要
XYChart.Series
XYChart.Data
,最后需要定义
StringConverter
作为格式化程序。正如@brian所说,您可以在任何
Number
实例上调用
intValue()。唯一的另一种方法是自己实现
ValueAxis
,而您不想这样做……或者,直接注入axis:
@FXML-private-NumberAxis-xAxis
这听起来像是FXML问题。我从来都不喜欢用FXML来制作图表,当时似乎有问题。显示您如何在FXML中声明轴和图表。之前的评论是我的错误,不知道您是否及时阅读。起初我移除了x轴,但由于范围和间隔不同,不清楚我的ping尖峰有多长。有时我会在最后一分钟放映,有时是一个小时。@brian我在帖子中添加了FXML。如果你在施法上仍然有困难,请使用James_D的解决方案,在NumberAxis上添加一个fx:id。也许控制器中的声明应该是LineChart我在使用格式化程序时遇到问题。我在问题的末尾添加了一些代码。
    class XAxisLabelConverter extends StringConverter<Integer> {

    double interval;
    int n;

    public XAxisLabelConverter(double interval, int n) {
        this.interval = interval;
        this.n = n;
    }

    @Override
    public Integer fromString(String arg0) {

        return null;
    }

    @Override
    public String toString(Integer value) {
        if (value < n) {
            return "";
        } else {
            return getTime(value.intValue() * interval);
        }
    }

}
    ((ValueAxis<Integer>) chart.getXAxis()).setTickLabelFormatter(new XAxisLabelConverter(
            Double.parseDouble(sField.getText()),size));
    xAxis.setTickLabelFormatter(new StringConverter<Number>() {
        @Override
        public String toString(Number object) {
            return (object.intValue() * 0.25) + "s";
        }

        @Override
        public Number fromString(String string) {
            return 0;
        }
    });