java JavaFX 图表轴标签格式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32740005/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaFX Chart axis label formatting
提问by Asalas77
I wrote a simple program to monitor my ping. I'm currently using NumberAxis
with auto ranging, and after each ping, I add the new data at the end, remove the first one and increment totalCount
variable for X axis position.
我写了一个简单的程序来监控我的 ping。我目前正在使用NumberAxis
自动范围,在每次 ping 之后,我在最后添加新数据,删除第一个并增加totalCount
X 轴位置的变量。
I would like the X axis label to either:
我希望 X 轴标签为:
- show time elapsed since start. So for example, the label for 1100th ping at 0.25s ping intervals would be
4m 35s
- show time since the ping. This would require the labels to remain static (not move with the plot) and be in reversed order.
- 显示自开始以来经过的时间。因此,例如,以 0.25 秒 ping 间隔进行的第 1100 次 ping 的标签将是
4m 35s
- 自ping显示时间。这将要求标签保持静态(不随图移动)并以相反的顺序排列。
Is either of these two (preferably 1st) possible to implement? I suppose I would have to use CategoryAxis
for this, but I'm not sure how to create unlimited number of categories and choose to show only full minutes. Is it possible to keep the NumberAxis
for easier use with incoming data and just change the label text formatting? I already have a method that converts seconds to 00h 00m 00s
format.
这两个(最好是第一个)中的任何一个都可以实施吗?我想我将不得不为此使用CategoryAxis
,但我不确定如何创建无限数量的类别并选择仅显示完整分钟。是否可以保留NumberAxis
传入数据以便于使用并更改标签文本格式?我已经有了一种将秒转换为00h 00m 00s
格式的方法。
Also another thing, I think related to auto ranging, the chart doesn't refresh after every input, but only once it exceeds 10% of given range. So for 1000 range as in the picture, it will draw 100 new pings, and then move everything 100 positions to the left. Can I change it somehow to move after just 1 ping?
还有一件事,我认为与自动范围有关,图表不会在每次输入后刷新,但只会在超过给定范围的 10% 时刷新。因此,对于如图所示的 1000 范围,它将绘制 100 个新 ping,然后将所有内容向左移动 100 个位置。我可以改变它以某种方式在 1 ping 后移动吗?
Not sure if relevant, but I'll post the code:
不确定是否相关,但我会发布代码:
Controller
控制器
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())));
}
}
}
Ping Task
Ping 任务
public class PingTask extends Task<Integer> {
int time;
String address;
public PingTask(String text) {
address = text;
}
@Override
protected Integer call() throws Exception {
try {
String cmd = "";
if (System.getProperty("os.name").startsWith("Windows")) {
cmd = "ping -n 1 " + address;
} else {
cmd = "ping -c 1 " + address;
}
Process process = Runtime.getRuntime().exec(cmd);
process.waitFor();
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String inputLine = in.readLine();
while ((inputLine != null)) {
if (inputLine.startsWith("Reply from")) {
String[] parts = inputLine.split("[ =ms]");
time = Integer.parseInt(parts[9]);
break;
}
inputLine = in.readLine();
}
} catch (Exception e) {
e.printStackTrace();
}
return time;
}
}
FXML
文件格式
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.GuiController">
<center>
<LineChart fx:id="chart" alternativeRowFillVisible="false" animated="false" createSymbols="false" horizontalZeroLineVisible="false" legendVisible="false" maxHeight="1.7976931348623157E308" verticalGridLinesVisible="false" verticalZeroLineVisible="false" BorderPane.alignment="CENTER">
<xAxis>
<NumberAxis animated="false" forceZeroInRange="false" minorTickCount="0" minorTickLength="0.0" minorTickVisible="false" side="BOTTOM" tickMarkVisible="false" tickUnit="1.0" upperBound="200.0" />
</xAxis>
<yAxis>
<NumberAxis animated="false" autoRanging="false" forceZeroInRange="true" minorTickCount="0" minorTickLength="0.0" minorTickVisible="false" side="LEFT" tickLabelGap="5.0" tickUnit="20.0" />
</yAxis>
</LineChart>
</center>
<left>
<VBox alignment="TOP_CENTER" spacing="10.0" BorderPane.alignment="CENTER">
<children>
<HBox alignment="CENTER" VBox.vgrow="NEVER">
<children>
<Label text="IP " />
<TextField fx:id="ipField" prefWidth="100.0" text="euw.leagueoflegends.com">
<opaqueInsets>
<Insets />
</opaqueInsets>
</TextField>
</children>
<padding>
<Insets top="5.0" />
</padding>
</HBox>
<HBox alignment="CENTER" VBox.vgrow="NEVER">
<children>
<Label text="Ping co " />
<TextField fx:id="sField" alignment="TOP_RIGHT" prefWidth="60.0" text="0.25" HBox.hgrow="NEVER">
<HBox.margin>
<Insets right="5.0" />
</HBox.margin>
</TextField>
<Label text="s" />
</children>
<padding>
<Insets top="5.0" />
</padding>
</HBox>
<HBox alignment="CENTER">
<children>
<Label text="Rysuj " />
<TextField fx:id="nField" alignment="CENTER_RIGHT" prefWidth="60.0" text="1000" HBox.hgrow="NEVER" />
<Label text=" próbek" />
</children>
<padding>
<Insets top="5.0" />
</padding>
</HBox>
<HBox alignment="CENTER" VBox.vgrow="NEVER">
<children>
<Label text="Poka? " />
<Label fx:id="timeLabel" text="0h 4m 10s" />
</children>
</HBox>
<HBox alignment="CENTER" spacing="10.0" VBox.vgrow="NEVER">
<children>
<Button fx:id="startButton" mnemonicParsing="false" onAction="#start" prefWidth="50.0" text="Start" />
<Button fx:id="stopButton" mnemonicParsing="false" onAction="#stop" prefWidth="50.0" text="Stop" />
</children>
</HBox>
<Label fx:id="pingLabel" text="0ms" textAlignment="CENTER">
<font>
<Font name="System Bold" size="40.0" />
</font>
</Label>
</children>
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</VBox>
</left>
</BorderPane>
EDIT
编辑
I tried using the formatter, but I'm getting ClassCastException: java.lang.Double cannot be cast to java.lang.Integer
at application.GuiController$XAxisLabelConverter.toString(GuiController.java:1) and I don't know what to do with it.
我尝试使用格式化程序,但我得到ClassCastException: java.lang.Double cannot be cast to java.lang.Integer
了 application.GuiController$XAxisLabelConverter.toString(GuiController.java:1) 并且我不知道如何处理它。
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);
}
}
}
In the start()
method
在start()
方法中
((ValueAxis<Integer>) chart.getXAxis()).setTickLabelFormatter(new XAxisLabelConverter(
Double.parseDouble(sField.getText()),size));
回答by brian
You can add a formatter to a number axis.
You may just want to remove the x-axis. It doesn't really add any information. If you're just showing the last 100 pings which were .25 secs apart, then you don't really need an axis to know when they happened.
您可能只想删除 x 轴。它并没有真正添加任何信息。如果您只是显示相隔 0.25 秒的最后 100 次 ping,那么您真的不需要轴来知道它们何时发生。
The chart is only moving after 100 pings due to the range of the axis. The interval will depend on the total range. The only way to change this is to shut off auto-ranging and set max, min, size yourself. You could use this constructor.
由于轴的范围,图表仅在 100 次 ping 后移动。间隔将取决于总范围。改变这一点的唯一方法是关闭自动量程并自己设置最大、最小、大小。你可以使用这个构造函数。
If you want to format you'll need a specialized converter since you need to modify the number. The Chart<..,Number> needs to convert a Number to a String so use a StringConverter<Number>
,eg.
如果你想格式化你需要一个专门的转换器,因为你需要修改数字。Chart<..,Number> 需要将数字转换为字符串,因此请使用StringConverter<Number>
,eg。
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;
}
});
ps. I've only used this on windows but you can see if it performs better than a new process.
附:我只在 Windows 上使用过它,但您可以查看它是否比新进程性能更好。
http://docs.oracle.com/javase/7/docs/api/java/net/InetAddress.html#isReachable(int)
http://docs.oracle.com/javase/7/docs/api/java/net/InetAddress.html#isReachable(int)