2015-09-23 3 views
1

Я написал простую программу для мониторинга моего пинга. В настоящее время я использую NumberAxis с автоматическим ранжированием, и после каждого пинга я добавляю новые данные в конец, удаляю первый и увеличиваю totalCount переменную для оси X.Форматирование меток оси JavaFX

Я хотел ось X метки либо:

  • показывает время, прошедшее с момента старта. Так, например, ярлык для 1100-го пинга с интервалами ping 0,25 с будет 4m 35s
  • показать время со времени пинга. Это потребует, чтобы метки оставались статическими (не двигались с графиком) и находились в обратном порядке.

Возможно ли реализовать одно из этих двух (предпочтительно 1-го) варианта? Я полагаю, что мне нужно было бы использовать CategoryAxis, но я не уверен, как создать неограниченное количество категорий и выбрать только полные минуты. Можно ли сохранить NumberAxis для удобства использования с входящими данными и просто изменить форматирование текста на этикетке? У меня уже есть метод, который преобразует секунды в формат 00h 00m 00s.

Также, я думаю, что это связано с автоматическим ранжированием, график не обновляется после каждого входа, а только один раз превышает 10% заданного диапазона. Так что для 1000 диапазонов, как на картинке, он будет нарисовать 100 новых пинов, а затем переместить все 100 позиций влево. Могу ли я изменить его как-то, чтобы двигаться после всего лишь одного пинга?

ping

Не уверен, если это необходимо, но я выложу код:

контроллер

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

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

Я попытался с помощью форматера, но я получаю 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); 
     } 
    } 

} 

В методе start()

((ValueAxis<Integer>) chart.getXAxis()).setTickLabelFormatter(new XAxisLabelConverter(
      Double.parseDouble(sField.getText()),size)); 
+2

сходиться к MCVE можно также разместить FXML. –

+0

@UlukBiy добавил FXML. – Asalas77

+1

Вы пытаетесь изменить узкое определение NumberAxis. Объявление - это публичный конечный класс NumberAxis, который расширяет ValueAxis '. Я не эксперт по типам, но я думаю, что лучше просто использовать Number и получить intValue(). – brian

ответ

4

Вы можете добавить formatter to a number axis.

Вы можете просто удалить ось x. На самом деле это не добавляет никакой информации. Если вы просто показываете последние 100 пингов, которые были на расстоянии 0,25 секунды, вам действительно не нужна ось, чтобы знать, когда они произошли.

График перемещается только после 100 пинов из-за диапазона оси. Интервал будет зависеть от общего диапазона. Единственный способ изменить это - отключить автоматическое определение и установить максимальный, минимальный размер. Вы можете использовать этот constructor.

Если вы хотите отформатировать, вам понадобится специализированный конвертер, так как вам нужно будет изменить номер. Диаграмма < .., Number> необходимо преобразовать Number в строку, поэтому используйте StringConverter<Number>, например.

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; 
     } 
    }); 

пс. Я использовал это только в окнах, но вы можете увидеть, работает ли он лучше, чем новый процесс.

http://docs.oracle.com/javase/7/docs/api/java/net/InetAddress.html#isReachable(int)

+0

Это звучит как проблема FXML. Мне никогда не нравилось использовать FXML для графиков, в то время это казалось проблематичным. Покажите, как вы указали ось и диаграмму в FXML. – brian

+0

Предыдущий комментарий был моим плохим, не знаю, прочитаете ли вы это вовремя. Первоначально у меня была ось x, но с разным диапазоном и интервалами, было непонятно, как долго мои пинговые пики были. Иногда я показываю последнюю минуту, а иногда и один час. – Asalas77

+0

@brian Я добавил FXML к сообщению. – Asalas77

Смежные вопросы