我有两个ComboBox:
final ComboBox<MainCategory> comboBoxMainCategory = new ComboBox<>();
final ComboBox<SubCategory> comboBoxSubCategory = new ComboBox<>();
根据comboBoxMainCategory中选择的值,comboBoxSubCategory应填充相应的枚举。
public enum MainCategory { // extra enum class
EUROPE("Europe"),
USA("USA");
}
public enum SubCategoryEurope { // extra enum class
GERMANY("Germany"),
FRANCE("France");
}
public enum SubCategoryUSA {
COLORADO("Colorado"),
CALIFORNIA("California");
}
如果&#34;欧洲&#34;如果为comboBoxMainCategory选择,则应使用SubCategoryEurope填充comboBoxSubCategory。如果&#34; USA&#34;,使用SubCategoryUSA。
你是如何实现这一目标的?
这是我的代码:
final ComboBox<MainCategory> comboBoxMainCategory = new ComboBox<();
final ComboBox<SubCategory> comboBoxSubCategory = new ComboBox<>();
comboBoxMainCategory.valueProperty().addListener((obs, oldValue,
newValue) ->
{
if (newValue == null) { // newValue: Europe || USA
comboBoxSubCategory.getItems().clear();
comboBoxSubCategory.setDisable(true);
} else if (newValue.equals(MainCategory.EUROPE)) {
comboBoxSubCategory.setItems(FXCollections.observableArrayList(SubCategoryEurope.values()));
comboBoxSubCategory.setDisable(false);
} else {
comboBoxSubCategory.setItems(FXCollections.observableArrayList(SubCategoryUSA.values()));
comboBoxSubCategory.setDisable(false);}
});
问题是,因为comboBoxSubCategory是&#34; SubCategory&#34;,如果用“SubCategoryEurope&#39;”填充了类型错误。或者&#39; SubCategoryUSA&#39;。
解决此问题的最佳方法是什么?对不起,如果这是一个愚蠢的问题,我是JavaFx的新手。
非常感谢!
答案 0 :(得分:1)
我根本不会使用枚举,因为这不允许在不重新编译的情况下进行数据操作。如果您坚持使用枚举,则需要使用<template>
<div> {{propValue.value}} </div>
</template>
<script>
export default {
props: ['propFunction', 'propValue'],
created(){
if (this.propValue.bool === true) {
this.propFunction()
}
}
}
</script>
或使用两个子类别枚举类型实现的接口作为Object
的参数类型:
comboBoxSubCategory
更好的方法是使用comboBoxMainCategory.valueProperty().addListener((obs, oldValue, newValue) -> {
if (newValue == null) { // newValue: Europe || USA
comboBoxSubCategory.getItems().clear();
comboBoxSubCategory.setDisable(true);
} else {
comboBoxSubCategory.setDisable(false);
List<? extends Object> list;
switch (newValue) {
case EUROPE:
list = Arrays.asList(SubCategoryEurope.values());
break;
default:
list = Arrays.asList(SubCategoryUSA.values());
break;
}
comboBoxSubCategory.getItems().setAll(list);
}
});
来存储数据:
Map<String, List<String>>
答案 1 :(得分:0)
创建通用占位符界面
public interface EnumPlaceHolder<E extends Enum<?>> {
public abstract String getDisplayValue();
public abstract E getEnum();
}
为您的所有枚举创建一个实现。例如
public class EuropePlaceholder implements EnumPlaceHolder<Europe> {
private final Europe value;
public EuropePlaceholder(Europe pValue){
value = pValue;
}
@Override
public String getDisplayValue() {
// here you create a user-friendly version of your enum for display
return value.toString();
}
@Override
public Europe getEnum() {
return value;
}
}
然后将ComboBox<Enum>
的类型更改为ComboBox<EnumPlaceholder<?>>
,您可以将任何已实施的EnumPlaceholders
添加到其中。检索所选项目时,您可以通过实例检查检查包含哪一项
EnumPlaceholder<?> selectedItem = ...;
if(selectedItem instanceof EuropePlaceholder){
Europe selectedEuropeEnum = (Europe) selectedItem.getEnum();
} else if(....){
// check with else if for your other enums
}
要在你的组合框中显示你的枚举,你可以调用EnumPlaceholder的getDisplayValue()
并在你的单元格中显示返回的String
:)
修改强> 总的来说,我必须同意法比亚人的回答。你不应该使用枚举这样的结构。而是使用Map&lt;&gt;或列表&lt;&gt;具有适当的内容和结构。
答案 2 :(得分:0)
只是为了好玩(以及充实我的评论):比其他答案更通用的方法是将感兴趣的焦点从支持数据的具体性质转移到更普遍的使用解决方案 - 手头的情况。让UI实现特殊情况的缺点总是相同的 - 您必须为每个特殊UI和每种特殊数据类型反复执行。出路总是一样的:实现一个接管一般方面的模型,并在具体的UI /数据上下文中重用它。
这里的一般方面是:
一般方法是建立一个
模型这种模型的优点是
在下面的示例中,Model名为RelationModel,它期望RelationProvider类型的根项(允许访问依赖项列表,它是一个选项,也可以使用函数来构建依赖项) )。它使用一个普通的字符串/列表映射,一次使用大陆/国家的枚举,每个都很容易实现。请注意,由此产生的UI幸福地不知道数据的性质,仅针对模型实现。
当然,不是生产等级,特别是没有经过正式测试,而且只有最基本的功能的模型:)
public class CombosWithCategories extends Application {
public interface RelationProvider<T> {
default ObservableList<T> getRelations() {
return emptyObservableList();
};
}
/**
* A model that manages a list of RelationProviders and has the notion
* of a current relationProvider with relations (it's a kind-of selectionModel).
*
* <T> the type of elements in the list of relations
*/
public static class RelationModel<T> {
/**
* all relationProviders managed by this model
*/
private ListProperty<RelationProvider<T>> relationProviders;
/**
* The owner of the relations. Must be contained in the providers managed
* by this model.
*/
private ObjectProperty<RelationProvider<T>> relationProvider;
private ListProperty<T> relations;
public RelationModel() {
initProperties();
}
/**
* The RelationProviders managed by the model.
*/
public ListProperty<RelationProvider<T>> relationProvidersProperty() {
return relationProviders;
}
/**
* The RelationProvider that manages the current relations.
*/
public ObjectProperty<RelationProvider<T>> relationProviderProperty() {
return relationProvider;
}
public RelationProvider<T> getRelationProvider() {
return relationProviderProperty().get();
}
public ListProperty<T> relations() {
return relations;
}
/**
* Callback from invalidation of current relationProvider.
* Implemented to update relations.
*/
protected void relationProviderInvalidated() {
RelationProvider<T> value = getRelationProvider();
relations().set(value != null ? value.getRelations() : emptyObservableList());
}
/**
* Creates and wires all properties.
*/
private void initProperties() {
relationProviders = new SimpleListProperty<>(this, "relationProviders", observableArrayList());
relationProvider = new SimpleObjectProperty<>(this, "relationProvider") {
@Override
protected void invalidated() {
// todo: don't accept providers that are not in the list
relationProviderInvalidated();
}
};
relations = new SimpleListProperty<>(this, "relations");
relationProviderInvalidated();
}
}
/**
* Implement the ui against a RelationModel. Here we create
* the same UI with a model backed by enums or a Map, respectively
*/
private Parent createContent() {
TabPane tabPane = new TabPane(
new Tab("Enums", createRelationUI(createEnumRelationModel())),
new Tab("Manual map", createRelationUI(createMapRelationModel()))
);
return new BorderPane(tabPane);
}
/**
* Common factory for UI: creates and returns a Parent that
* contains two combo's configured to use the model.
*/
protected <T> Parent createRelationUI(RelationModel<T> model) {
ComboBox<RelationProvider<T>> providers = new ComboBox<>();
providers.itemsProperty().bind(model.relationProvidersProperty());
providers.valueProperty().bindBidirectional(model.relationProviderProperty());
ComboBox<T> relations = new ComboBox<>();
relations.itemsProperty().bind(model.relations());
relations.valueProperty().addListener((src, ov, nv) -> {
LOG.info("relation changed: " + nv);
});
return new VBox(10, providers, relations);
}
// ------------- manual with maps
/**
* On-the-fly creation of a RelationModel using a backing map.
*/
protected RelationModel<String> createMapRelationModel() {
RelationModel<String> model = new RelationModel<>();
Map<String, ObservableList<String>> data = new HashMap<>();
data.put("EUROPE", observableArrayList("GERMANY", "FRANCE"));
data.put("AMERICA", observableArrayList("MEXICO", "USA"));
for (String key: data.keySet()) {
model.relationProvidersProperty().add(new RelationProvider<String>() {
@Override
public ObservableList<String> getRelations() {
return data.get(key);
}
@Override
public String toString() {
return key;
}
});
}
return model;
}
//-------------------- enum
/**
* RelationModel using Enums.
*/
protected RelationModel<Object> createEnumRelationModel() {
RelationModel<Object> model = new RelationModel<Object>();
model.relationProvidersProperty().setAll(Continent.values());
return model;
}
public enum EuropeanCountry {
FRANCE, GERMANY;
}
public enum AmericanCountry {
MEXICO, CANADA, USA;
}
public enum Continent implements RelationProvider<Object> {
AMERICA(AmericanCountry.values()),
EUROPE(EuropeanCountry.values())
;
ObservableList<Object> subs;
private Continent(Object[] subs) {
this.subs = FXCollections.observableArrayList(subs);
}
@Override
public ObservableList<Object> getRelations() {
return FXCollections.unmodifiableObservableList(subs);
}
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(CombosWithCategories.class.getName());
}