当前位置: 首页 > 知识库问答 >
问题:

Javafx:如何将ComboBox项目动态绑定到从数据库更新自身的观察列表

蓬琦
2023-03-14

我试图将我的javafx组合框项目绑定到observablelist;当列表更新时,组合框项目也会更新(添加、删除或修改)。我试图将侦听器添加到组合框项目中,但仍然出现“Not on FX application thread”异常。这是我的代码:

模型

{
    …
    private ObservableList<String> programList = FXCollections.observableArrayList();

    …
    some code initialize programList from database
    …

    private ListProperty<String> programListProperty = new SimpleListProperty<>(programList);

    …
    some code update programList periodically
    …

    }

控制器呢

{
    @FXML ComboBox programComboBox;


    model.programListProperty().addListener((v, oldValue, newValue) -> 
    Platform.runLater(() -> {
        programComboBox.getItems().clear();
        programComboBo.getItems().add(every item in model.programList);
    }));
}

我也试过这种方法,但都不管用

{
    @FXML ComboBox programComboBox;

    programComboBox.itemsproperty().bind(model.programListProperty());

}

共有2个答案

岳意蕴
2023-03-14

既然你还没有发布一个MCVE,我们只能做这么多来帮助你,这里有一个例子,说明你在努力做什么,我尽了最大努力模仿你已经拥有的东西,你必须看到什么对你不起作用,并纠正它,但这里有一个例子,说明我做了什么,经过测试,对我有效

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        Model model = new Model();

        ComboBox<String> comboBox = new ComboBox<>();
        comboBox.itemsProperty().bind(model.getProgramListProperty());

        VBox vBox = new VBox();
        vBox.setAlignment(Pos.CENTER);
        vBox.getChildren().add(comboBox);

        primaryStage.setScene(new Scene(vBox));
        primaryStage.show();
    }

    public static void main(String[] args) { launch(args); }

}

模范班

public class Model{

    private ObservableList<String> programList = FXCollections.observableArrayList();
    private ListProperty<String> programListProperty = new SimpleListProperty<>(programList);

    Model(){
        updateListFromDatabase();
        continuousDatabaseUpdate();
    }

    ListProperty<String> getProgramListProperty() {
        return programListProperty;
    }

    private void continuousDatabaseUpdate() {
        new Timer().schedule( //Schedule a timer to fire a task at an interval
                new TimerTask() {//Create a new TimerTask that runs a list update
                    @Override
                    public void run() {//What its running
                        //Important my update is wrapped in Platform.runLater so I DON'T block the main thread
                        Platform.runLater(() -> updateListFromDatabase());
                    }
                },
                0,//Delay 0
                2/*Number of seconds*/ * 1000/*turn milliseconds into seconds*/);
    }

    private void updateListFromDatabase(){//Create a list of varying size and changing numbers
        programList.clear();//Clear current list 
        double size = Math.random() * 10 + 1;
        for (int i = 0; i < size; i++) {
            programList.add(String.valueOf(Math.random() * 20 + 1));//Add random values
        }
    }
}

这可能不是最佳解决方案,因为我们看不到您在MCVE中尝试做什么,您刚刚发布了一些代码,并希望其他人来填充其余的代码

此外,我不建议在列表中添加侦听器,我会在您与数据库对话时检查列表是否需要更新。下面是我引用的内容

model.programListProperty().addListener((v, oldValue, newValue) -> 
    Platform.runLater(() -> {
        programComboBox.getItems().clear();
        programComboBo.getItems().add(every item in model.programList);
    }));

否则这就是数据流

检查数据库更改-

VS

检查数据库更改-

除非你的html" target="_blank">数据库在更新时通知你,否则你的方式是有意义的,我怀疑,因为你说“一些代码定期更新程序列表”,这就是为什么MCVE会有帮助

王涵育
2023-03-14

注意:这个解决方案对您的实现做了一些假设,因为您没有提供一个最小的、完整的、可验证的代码示例。

您不需要为此使用绑定。组合框使用可观察列表填充其项。这里的关键词是可观察的。这意味着,当基础的列表更改时,组合框将“看到”更改并自动更新其显示的项目。

使用setItems()方法初始化ComboBox,并将observeList作为参数传递给它:

comboBox.set项目列表

从那里,每当更新程序列表时(添加、删除项目等),组合框将反映更改,而无需您提供任何进一步的代码。

查看以下完整示例:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class ComboBoxListenerExample extends Application {

    // This is our ObservableList that will hold our ComboBox items
    private ObservableList<String> items = FXCollections.observableArrayList();

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        // Simple interface
        VBox root = new VBox(5);
        root.setPadding(new Insets(10));
        root.setAlignment(Pos.CENTER);

        // Simple ComboBox
        ComboBox<String> comboBox = new ComboBox<>();

        // Let's "permanently" set our ComboBox items to the "items" ObservableList. This causes the
        // ComboBox to "observe" the list for changes
        comboBox.setItems(items);

        // Create a button that will reload data from our "database"
        Button button = new Button("Refresh Data");

        // The items.setAll()` method replaces all items in the list with our new list of items
        button.setOnAction(event -> items.setAll(reloadDatabase()));

        root.getChildren().addAll(comboBox, button);

        // Show the Stage
        primaryStage.setWidth(300);
        primaryStage.setHeight(300);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    // Sample method to simulate reloading the database information
    private List<String> reloadDatabase() {

        List<String> items = new ArrayList<>();

        for (int i = 0; i < 5; i++) {
            items.add(getRandomWord());
        }
        return items;

    }

    // Just a helper method specific for this example; it simply returns a random word. 
    // This is used to simulate loading new data from the database
    private String getRandomWord() {

        List<String> words = Arrays.asList("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Red", "Blue", "Green", "Yellow", "Left", "Right", "Top", "Bottom");
        Random random = new Random();
        return words.get(random.nextInt(words.size()));
    }
}

运行示例时,组合框为空。每次单击“刷新数据”按钮时,基础的可观察列表,都会用新的随机项列表进行更新;组合框会立即更改以反映这些更改。

不在JavaFX应用程序线程上:

那么,那个错误消息呢?关于StackOverflow,有很多问题和答案已经解决了这个问题,但这里有一个简短的解释:

我假设您正在后台线程上从数据库加载数据,这很好!但是,您不能从该线程对用户界面进行任何更改或更新。所有用户界面更新都需要在JavaFX应用程序线程上完成。

这非常简单。当您在调用数据库方法时更新List时,将该更新包装在一个Platform.run稍后()调用中:

Platform.runLater(() -> programList.setAll(yourNewList));

这将在JFX应用程序线程上对列表进行更新。问题解决了!

 类似资料:
  • 我需要帮助,以获得一个指定的项目列表,并将它们添加到组合框。 我的观察列表包含从数据库接收的值(在特定的只有3列的表中),我想在组合框中只显示一个列值。选择组合框时,其他值在2个文本字段中收费。 代码如下。 导入Accettazioni模型: 重要信息控制器: 现在,逻辑似乎工作正常,但是我的组合框不包含值nomeProperty()。 我该如何解决? 预先感谢

  • 我在使用可观察类制作DropDownList时遇到问题。 下面是可观察类的代码: 这是我的工作下拉列表: 这是我的DropDownList的html: 最后,这是我从observable datasource请求中得到的结果: 我做了一些研究,但找不到任何合适的例子。 我看了看:MVVM小部件绑定和周围玩数据绑定,数据值字段,数据文本字段,但不能得到我想要的结果。 因此,我正在寻找的是一种将常规D

  • 我是FX新手,对Java不太陌生,所以请耐心等待!我有一个简单的应用程序,它使用一个由ObservableList支持的JavaFX TableView。 当我第一次启动应用程序时,我生成了另一个Thread(从Application的start方法)来监听对日志文件的更改并将另一个元素添加到观察列表中,以便在TableView中立即可见该行。我认为在窗口中有一个包含当前大小的Label会很有好处

  • 我有动态文本要绑定到HTML页面上。这是一个Angular 2应用程序。我正在使用这样的东西: 但是我收到一个错误: 无法绑定到“aria-label ”,因为它不是“div”的已知属性。 对此有什么解决方法吗?

  • 我正在用一个库编程,我不知道代码,只知道方法,我不能修改它。我试着制作一个“航班”的表格视图,但我不知道如何为每个航班命名(或ID)。有人能帮我吗?谢谢此处有一些代码: