3

我有一个带有 JafavaFx 的表格视图,用于每秒显示给用户货币。一切正常,但是当 tableView 尝试重新加载数据时,它会在几毫秒内停止,我的意思是冷冻机,看起来不太漂亮。我无法删除此行为,此时我使用的代码是:

setCache(true);

        setItems(getObservableList());
        Timeline animation = new Timeline();
        animation.getKeyFrames().add(new KeyFrame(Duration.seconds(1), new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                setItems(getObservableList());                  
            }
        }));
        animation.setCycleCount(Animation.INDEFINITE);
        animation.play();

我的表列

getColumns().addAll(
            getStringField("id","Tikect"), 
            getStringField("currency","Symbol"), 
            getStringField("type","S/B"), 
            getDoubleField("amount","Amt (k)"), 
            getDoubleField("open","Open"), 
            getDoubleField("close","Close"),
            getDoubleField("stop","Stop"), 
            getDoubleField("limit","Limit"), 
            getDoubleField("pl","P/L"), 
            getDoubleField("gpl","Gross P/L")
            );

在添加列的其他类中,我有一个这样的功能:

    public static TableColumn<BaseModel, String> getStringField(String idColumn,String nameColumn) {
    TableColumn<BaseModel, String> column = new TableColumn<BaseModel, String>(idColumn);
    column.setCellValueFactory(new PropertyValueFactory<BaseModel, String>(idColumn));
    column.setMinWidth(100);
    column.setText(nameColumn);

    return column;
}

我的 ObservableList 是:

public ObservableList<BaseModel> getObservableList() throws IOException {
    ObservableList<BaseModel> oTransacctions = FXCollections.observableArrayList();

    JsonFactory factory = new JsonFactory();
    JsonParser jp = factory.createJsonParser(new URL(getURL()));

    JsonToken token = jp.nextToken();

    while (token != JsonToken.START_ARRAY) {
        token = jp.nextToken();
    }

    while (token != JsonToken.END_ARRAY) {
        token = jp.nextToken();

        if (token == JsonToken.START_OBJECT) {
            Transaction transaction = parseTransacction(jp);
            oTransacctions.add(transaction);
        }
    }

    return oTransacctions;
}

private Transaction parseTransacction(JsonParser jp) throws IOException {
    Transaction transaction = new Transaction();
    JsonToken token = jp.nextToken();

    while (token != JsonToken.END_OBJECT) {
        if (token == JsonToken.START_OBJECT) {
            while (token != JsonToken.END_OBJECT) {
                token = jp.nextToken();
            }
        }

        if (token == JsonToken.FIELD_NAME) {
            String fieldname = jp.getCurrentName();

            if ("id".equals(fieldname)) {
                jp.nextToken();
                transaction.setId(jp.getText());
            }
            if ("currency".equals(fieldname)) {
                jp.nextToken();
                transaction.setCurrency(jp.getText());
            }
            if ("type".equals(fieldname)) {
                jp.nextToken();
                transaction.setType(jp.getText());
            }
            if ("amount".equals(fieldname)) {
                jp.nextToken();
                transaction.setAmount(jp.getValueAsDouble());
            }
            if ("open".equals(fieldname)) {
                jp.nextToken();
                transaction.setOpen(jp.getValueAsDouble());
            }
            if ("stop".equals(fieldname)) {
                jp.nextToken();
                transaction.setStop(jp.getValueAsDouble());
            }
            if ("limit".equals(fieldname)) {
                jp.nextToken();
                transaction.setLimit(jp.getValueAsDouble());
            }
            if ("created_at".equals(fieldname)) {
                jp.nextToken();
                // transaction.setCreated_at(new Date(jp.getText()));
            }
            if ("pl".equals(fieldname)) {
                jp.nextToken();
                transaction.setPl(jp.getValueAsDouble());
            }
            if ("gpl".equals(fieldname)) {
                jp.nextToken();
                transaction.setGpl(jp.getValueAsDouble());
            }
            if ("close".equals(fieldname)) {
                jp.nextToken();
                transaction.setClose(jp.getDoubleValue());
            }
        }
        token = jp.nextToken();
    }

    return transaction;
}

这是结果:

在此处输入图像描述

我的问题是:

  • 我应该使用网格等其他组件,...来做这种类型的动作吗?
  • 如果可能的话我应该怎么做?

非常感谢 !

4

2 回答 2

3

看起来您正在某些方法中执行 I/O(至少throws IOException在其签名中有一个)。

您不应在 JavaFX 应用程序线程上执行任何 I/O,因为该线程处理用户界面。如果您确实在 JavaFX 应用程序线程上执行 I/O,那么您最终将阻塞线程并且程序将显示为对用户没有响应。

您要做的是将数据从服务器异步获取到客户端。为此,您应该使用 JavaFX 并发实用程序,例如TaskService。要注意的另一件事是,您的 I/O 获取线程不应直接更新您的 UI(甚至间接地ObservableList支持您的表)。

在你的情况下,我会做类似下面的代码:

final ForexService forex = new ForexService();
forex.setUrl(getUrl()); // getUrl() is some method your application provides 
forex.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
  @Override public void handle(WorkerStateEvent event) {
    setItems(forex.getValue());     
    forex.reset();             
  }
}           
forex.setOnFailed(new EventHandler<WorkerStateEvent>() {
  @Override public void handle(WorkerStateEvent event) {
    // exception handling with forex.getException()   
    forex.reset();             
  }
}           
...
Timeline animation = new Timeline();
animation.getKeyFrames().add(new KeyFrame(Duration.seconds(1), new EventHandler<ActionEvent>() {
  @Override public void handle(WorkerStateEvent event) {
    if (Worker.State.READY == forex.getState()) {
      forex.start();
    }
  } 
}));
animation.setCycleCount(Animation.INDEFINITE);
animation.play();
...
public static class ForexService extends Service<ObservableList<BaseModel>> {
  private StringProperty url = new SimpleStringProperty(this, "url");
  public final void setUrl(String value) { url.set(value); }
  public final String getUrl() { return url.get(); }
  public final StringProperty urlProperty() { return url; }

  protected Task createTask() {
    final String _url = getUrl();
    return new Task<ObservableList<BaseModel>>() {
      protected String call() throws Exception {
        // getObservableList is the function which actually fetches the
        // data from the server and processes it into an ObservableList
        // which can later be fed to a TableView.
        // This function is essentially the same as the function
        // supplied in your question.
        return getObservableList(new URL(_url));
      }
    };
  }
}

上面的代码只是在没有编译或测试的情况下输入 StackOverflow,所以你可能会在这里或那里有一些小错误,但我认为它为你提供了这个想法的要点。

您可能会注意到,所有关于将 url 传递给服务以使其无法在不同线程上修改的技巧都是直接从Servicejavadoc 示例中复制的。此外,如果您的 url 只是一些永远不会改变的静态事物,那么您可以将其编码为static final常量,而不必费心将其设为可变参数。

请注意,使用 TableView 不是问题(您可以使用 Grid 或任何其他控件,如果您阻止 Java 应用程序线程,您仍然会遇到问题)。

如果以上看起来只是为了进行服务器调用和获取一些数据需要做很多工作,那么应该注意的是,JavaFX(目前)只是为这些类型的事物提供服务的低级供应商。有 3rd 方库,例如DataFX,它们提供高级服务,用于执行诸如从各种来源异步获取数据、从各种格式(如 xml 和 json)解析数据以及填充各种 JavaFX 控件(如 TableViews 和 ListViews)之类的事情。

于 2013-02-27T10:14:01.100 回答
-1

您可能对使用 Highcharts 感兴趣,尤其是这个例子:http ://www.highcharts.com/stock/demo/dynamic-update

于 2013-02-26T07:04:03.550 回答