JavaFX:将textProperty从Label绑定到ObservableList的大小

时间:2013-11-11 22:06:59

标签: java binding javafx-2 javafx javabeans

我是FX新手,对Java不是新手,所以请耐心等待!我所拥有的是一个使用由ObservableList支持的JavaFX TableView的简单应用程序。

当我第一次启动应用程序时,我会生成另一个Thread(来自Application的start方法)来监听对日志文件的更改,并将另一个元素添加到ObservableList中,以便在TableView中可以立即看到该行。我认为在窗口中包含一个包含ObservableList当前大小的Label是有益的。我试图将Label的textProperty绑定到ObservableList的大小。我的第一次尝试产生了:

tableSizeLabel.textProperty().bind(Bindings.size((tableView.getItems())).asString());

但我相信我误解了Bindings API。我意识到ObservableList.size()返回一个常规的int而不是ObservableValue,它甚至可以工作,但我认为Bindings类有一个静态方法为我创建一个。

后端模型将列表作为静态变量包含在内(我省略了listen-for-changes部分):

public class LogFileListener implements Runnable {

private static final ObservableList<SNMPTrap> model = FXCollections.observableArrayList();

@Override
public void run() {
    String line = null;
    try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fileLocation)))) {
        while ((line = br.readLine()) != null) {
            model.add(parseTrap(line));
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }

}

public static ObservableList<SNMPTrap> getModel() {
    return model;
}

}

应用程序类:

public class TableDisplay extends Application {

@Override
public void start(Stage stage) throws Exception {

    new Thread(new LogFileListener()).start();

    Parent root = FXMLLoader.load(getClass().getResource("path/to/FXML"));

    Scene scene = new Scene(root);
    stage.setScene(scene);
    stage.show();

}

控制器类:

public class TableDisplayController implements Initializable {

@FXML
private TableView<SNMPTrap> tableView;
@FXML
private Label tableSizeLabel;

@Override
public void initialize(URL url, ResourceBundle rb) {

    tableView.setItems(LogFileListener.getModel());

    tableSizeLabel.textProperty().bind(Bindings.size((tableView.getItems())).asString());

}

这在FX中甚至可能吗?我是否需要向整个ObservableList添加更改侦听器,然后才用getSize()更新Label?

提前致谢!

1 个答案:

答案 0 :(得分:7)

您的绑定语句对于您想要实现的目标是正确的(将Label的text属性绑定到ObservableList的大小)。

您的代码存在并发问题。会发生什么是LogFileListener在其自己的线程中运行,更新项目列表并在LogFileListener线程中更新项目,从而触发JavaFX应用程序线程的场景图形更新。这是一个“坏事”,因为JavaFX使用单个GUI线程。

您需要做的是确保绑定触发器和表项更新仅发生在JavaFX应用程序线程上(您可能需要以有效的方式执行此操作,以便您不会使JavaFX事件处理器过载许多小更新电话)。

对当前解决方案的一个简单修复是使用以下代码。

final SNMPTrap trap = parseTrap(line);
Platfrom.runLater(new Runnable() {
  @Override public void run() {
    model.add(trap);
  }
});

您的应用程序可能会受益于更复杂的方法。您可以在Platform.runLater,任务,服务和JavaFX concurrency主题上搜索StackOverflow以获取相关问题,并在JavaFX和Task javadoc中查看有关并发性的Oracle文档,以便更好地了解所有这些内容工作和你的选择。