JavaFX图表轴标签格式
我写了一个简单的程序来监控我的ping。我目前正在使用带有自动测距功能的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来实现这一点
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;
}
});