如何将ComboBox绑定到JavaFX中的列表?

时间:2016-11-12 08:17:43

标签: list javafx combobox bind

我的应用程序会定期使用线程将字符串添加到列表。我想将这些字符串添加到列表后立即添加到 ComboBox 。无论如何将 ComboBox 绑定到列表

我的代码:

static final int max = 20;
List<String> ips = new ArrayList<String>();

public void getIP() throws UnknownHostException {

    Task task = new Task<Void>() {
        @Override
        public Void call() throws UnknownHostException {
            InetAddress localhost = InetAddress.getLocalHost();
            byte[] ip = localhost.getAddress();
            for (int i = 10; i <= max; i++) {
                if (isCancelled()) {
                    break;
                }
                try {
                    ip[3] = (byte) i;
                    InetAddress address = InetAddress.getByAddress(ip);

                    if (address.isReachable(100)) {
     //============================== Populating List ===============//
                        ips.add(address.getHostName());
                    }
                } catch (Exception e) {
                    System.err.println(e);
                }
                updateProgress(i, max);

            }
            return null;
        }
    };
    //============================== Bind ComboBox to List Code here ===============//
    indicator.progressProperty().bind(task.progressProperty());
    new Thread(task).start();
}

2 个答案:

答案 0 :(得分:0)

没有办法绑定一个简单的列表,因为它不可观察。即使使用ObservableList,也会出现来自不同线程的更新问题。

但是,您可以使用同步列表并使用value属性传递当前大小,这样您就可以通过侦听器添加项目。

示例

这使用ListView代替ComboBox,因为结果在没有用户互动的情况下可见,但您也可以使用targetList = comboBox.getItems()

@Override
public void start(Stage primaryStage) {
    ListView<String> listView = new ListView<>();
    List<String> targetList = listView.getItems();
    final List<String> ips = Collections.synchronizedList(new ArrayList<>());
    Task<Integer> task = new Task<Integer>() {

        @Override
        protected Integer call() throws Exception {
            Random random = new Random();
            int size;
            for (size = 0; size < 100; size++) {
                ips.add(Integer.toString(size));
                updateValue(size);
                Thread.sleep(random.nextInt(500));
            }

            return size;
        }

    };
    task.valueProperty().addListener((observable, oldValue, newValue) -> {
        // add values not yet in the target list.
        for (int i = targetList.size(), newSize = newValue; i < newSize; i++) {
            targetList.add(ips.get(i));
        }
    });

    new Thread(task).start();

    Scene scene = new Scene(listView);

    primaryStage.setScene(scene);
    primaryStage.show();
}

虽然简单地使用Platform.runLater在ui线程上发布更新会更简单:

ips = comboBox.getItems();

Task task = new Task<Void>() {
    @Override
    public Void call() throws UnknownHostException {
        InetAddress localhost = InetAddress.getLocalHost();
        byte[] ip = localhost.getAddress();
        for (int i = 10; i <= max; i++) {
            if (isCancelled()) {
                break;
            }
            try {
                ip[3] = (byte) i;
                InetAddress address = InetAddress.getByAddress(ip);

                if (address.isReachable(100)) {
 //============================== Populating List ===============//
                    final String hostName = address.getHostName();
                    // do update on application thread
                    Platform.runLater(() -> ips.add(hostName));
                }
            } catch (Exception e) {
                System.err.println(e);
            }
            updateProgress(i, max);

        }
        return null;
    }
};

答案 1 :(得分:0)

我建议你做以下事情:

变化

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

final ObservableList<String> ips = FXCollections.observableArrayList();

变化:

Task task = new Task<Void>()

Task<ObservableList<String> task = new Task<>(){
@Override
public ObservableList<String> call() throws UnknownHostException {
...
return ips;  
}
};
comboBox.itemsProperty().bind(task.valueProperty());