FXML动态初始化ComboBox和TableView的ObservableList [英] FXML Dynamically initialize ObservableList for ComboBox and TableView

查看:426
本文介绍了FXML动态初始化ComboBox和TableView的ObservableList的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将Dan Nicks的评论中建议的自定义生成器制作为

I am trying to make a custom builder proposed in Dan Nicks's comment to this question.
The idea is to set combo's data before constructing it.
combo.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ComboBox?>

<ComboBox  fx:id="combo1" items="${itemLoader.items}"  prefWidth="150.0" 
   xmlns:fx="http://javafx.com/fxml/1">
</ComboBox>

提供数据的类:

public class ComboLoader {

    public ObservableList<Item> items;

    public ComboLoader() {

        items = FXCollections.observableArrayList(createItems());
    }

    private List<Item> createItems() {
            return IntStream.rangeClosed(0, 5)
                    .mapToObj(i -> "Item "+i)
                    .map(Item::new)
                    .collect(Collectors.toList());
        }

    public ObservableList<Item> getItems(){

        return items;
    }

    public static class Item {

        private final StringProperty name = new SimpleStringProperty();

        public Item(String name) {
            this.name.set(name);
        }

        public final StringProperty nameProperty() {
            return name;
        }
     
    }
}

测试:

public class ComboTest extends Application {

    @Override
    public void start(Stage primaryStage) throws IOException {

        primaryStage.setTitle("Populate combo from custom builder");

        Group group = new Group();

        GridPane grid = new GridPane();
        grid.setPadding(new Insets(25, 25, 25, 25));
        group.getChildren().add(grid);

        FXMLLoader loader = new FXMLLoader();
        ComboBox combo = loader.load(getClass().getResource("combo.fxml"));
        loader.getNamespace().put("itemLoader", new ComboLoader());
        grid.add(combo, 0, 0);

        Scene scene = new Scene(group, 450, 175);

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

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

没有产生错误,但是没有填充组合.
缺少什么?

No errors produced, but combo is not populated.
What is missing ?


BTW:TableView的类似解决方案效果很好:


BTW: a similar solution for TableView works fine:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.cell.PropertyValueFactory?>

 <TableView items="${itemLoader.items}"   xmlns:fx="http://javafx.com/fxml/1">
     <columns>
         <TableColumn text="Item">
             <cellValueFactory><PropertyValueFactory property="name" /></cellValueFactory>
         </TableColumn>
     </columns>
 </TableView>

推荐答案

我从挑剔开始,做了一些实验,研究如何实际实现我在对

Starting from a nit-pick, I did some experiments on how to actually implement what I tried to outline in my comments to c0der's answer.

基本思想是对listCell采取与对数据相同的方法,即通过名称空间(我今天的学习内容)配置内容和外观.成分:

The basic idea is to follow the same approach for the listCell as for the data, that is configure both content and appearance via namespace (my learn item of the day). The ingredients:

  • 可配置为将项目转换为文本的函数的通用自定义listCell
  • 通用的"cellFactory工厂"提供用于创建该单元格的cellFactory的类
  • a generic custom listCell configurable with a function to convert an item to text
  • a generic "cellFactory factory" class for providing a cellFactory creating that cell

单位/工厂:

public class ListCellFactory<T> {
    
    private Function<T, String> textProvider;

    public ListCellFactory(Function<T, String> provider) {
        this.textProvider = provider;
    }

    public Callback<ListView<T>, ListCell<T>> getCellFactory() {
        return cc -> new CListCell<>(textProvider);
    }
    
    public ListCell<T> getButtonCell() {
        return getCellFactory().call(null);
    }
    
    public static class CListCell<T> extends ListCell<T> {
        
        private Function<T, String> converter;

        public CListCell(Function<T, String> converter) {
            this.converter = Objects.requireNonNull(converter, "converter must not be null");
        }

        @Override
        protected void updateItem(T item, boolean empty) {
            super.updateItem(item, empty);
            if (empty) {
                setText(null);
            } else {
                setText(converter.apply(item));
            }
        }
        
    }

}

用于创建和配置组合的fxml:

The fxml to create and configure the combo:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ComboBox?>

<ComboBox  fx:id="combo1" items="${itemLoader.items}"  
    cellFactory="${cellFactoryProvider.cellFactory}" 
    buttonCell = "${cellFactoryProvider.buttonCell}"
    prefWidth="150.0" 
   xmlns:fx="http://javafx.com/fxml/1">
</ComboBox>

使用它的示例:

public class LocaleLoaderApp extends Application {

    private ComboBox<Locale> loadCombo(Object itemLoader, Function<Locale, String> extractor) throws IOException {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("comboloader.fxml"));
        loader.getNamespace().put("itemLoader", itemLoader);
        loader.getNamespace().put("cellFactoryProvider", new ListCellFactory<Locale>(extractor));
        ComboBox<Locale> combo = loader.load();
        return combo;
    }
    
    @Override
    public void start(Stage primaryStage) throws IOException {

        primaryStage.setTitle("Populate combo from custom builder");

        Group group = new Group();
        GridPane grid = new GridPane();
        grid.setPadding(new Insets(25, 25, 25, 25));
        group.getChildren().add(grid);
        LocaleProvider provider = new LocaleProvider();
        grid.add(loadCombo(provider, Locale::getDisplayName), 0, 0);
        grid.add(loadCombo(provider, Locale::getLanguage), 1, 0);
        Scene scene = new Scene(group, 450, 175);

        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    public static class LocaleProvider {
        ObservableList<Locale> locales = FXCollections.observableArrayList(Locale.getAvailableLocales());
        
        public ObservableList<Locale> getItems() {
            return locales;
        }
    }
    

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

这篇关于FXML动态初始化ComboBox和TableView的ObservableList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆