JavaFX:将标签的textProperty绑定到ObservableList的大小

3
我虽然不是专业的FX开发人员,但我熟悉Java。现在我有一个简单的应用程序,使用JavaFX TableView支持ObservableList。当我首次启动应用程序时,我会从Application的start方法中另外启动一个线程来监听日志文件的变化,并将另一个元素添加到ObservableList中,以便该行立即在TableView中可见。我想在窗口中添加一个标签,显示ObservableList的当前大小。我试图将Label的textProperty绑定到ObservableList的大小上。我的第一次尝试失败了:
tableSizeLabel.textProperty().bind(Bindings.size((tableView.getItems())).asString());
我认为我对Bindings API存在误解。我意识到ObservableList.size()返回的是普通int而不是必需的ObservableValue,但我认为Bindings类有一个静态方法可以为我创建ObservableValue。
后端模型将列表作为静态变量包含(我省略了监听更改部分):
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();

}

控制器类:
The Controller Class:
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个回答

10

您的绑定语句对于您想要实现的内容(将Label的文本属性绑定到ObservableList的大小)是正确的。

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

您需要确保绑定触发和表格项更新仅在JavaFX应用程序线程上发生(您可能需要以有效的方式这样做,以便不会通过太多小的更新调用来过载JavaFX事件处理器)。

您当前解决方案的简单修复方法是使用以下代码。

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

您的应用程序可能会从更复杂的方法中受益。您可以在StackOverflow上搜索有关Platform.runLater、Task、Service和JavaFX并发主题的相关问题,以及查看Oracle关于JavaFX并发的文档和Task javadoc(链接1),以更好地了解所有这些内容如何工作以及您的选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接