我正在研究JavaFX,我正在关注ChoiceBoxes。问题很简单:如果选择框应该承载异构数据,为什么它们要参数化?
由此导致的一个问题是无法实现官方指南的示例:http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/choice-box.htm。
我有这样的代码:
final String[] greetings = new String[] { "Hello", "Hola", "Olá"};
final ChoiceBox cb2 = new ChoiceBox(
FXCollections.observableArrayList("English", "Español", "Portuguese"));
final Label theText = new Label(greetings[0]);
cb2.getSelectionModel().selectedItemProperty().addListener(
(ObservableValue<? extends Number> ov, Number oldValue, Number newValue) ->
theText.setText(greetings[newValue.intValue()])
);编译器报告lambda无效,因为它具有与CheckBox类不兼容的类型,该类包含String类型,即使它没有被参数化。但是如果我使用<Object>参数化CheckBox,我将需要将newValue转换为number类型,并且在运行时我得到一个ClassCastException,说明它不能将字符串转换为Number。
为什么ChoiceBox类会将您锁定为唯一可用的类型?Choicebox应该支持异构数据。
还有:有了这个问题,我该如何实现官方的向导示例?
发布于 2014-09-09 00:52:02
我猜您希望selectedItem属性是所选项目的索引:其实不然:它是实际的项目本身。因此,如果您要将String放入其中,则需要向所选项目注册一个ChangeListener<String>。
索引是selectedIndex属性。所以你可以这样做
final String[] greetings = new String[] { "Hello", "Hola", "Olá"};
final ChoiceBox<String> cb2 = new ChoiceBox<String>(
FXCollections.observableArrayList("English", "Español", "Portuguese"));
final Label theText = new Label(greetings[0]);
cb2.getSelectionModel().selectedItemProperty().addListener(
(ObservableValue<? extends String> ov, String oldValue, String newValue) ->
System.out.println("Selected language is: "+newValue)
);
cb2.getSelectionModel().selectedIndexProperty().addListener(
(ObservableValue<? extends Number> ov, Number oldIndex, Number newIndex) ->
theText.setText(greetings[newValue.intValue()])
);至于“为什么它们是参数化的”这个问题,是为了让你可以声明那里的数据类型,然后检索正确的类型。如果您的ComboBox确实是异构的(即它包含混合数据类型),那么您可以做的最好的事情就是将它声明为其中所有数据中最具体的公共超类。(您可能想问一下这是不是一个好的设计选择。)
举个例子:
ChoiceBox<Object> mixedChoices = new ChoiceBox<>();
// Put any Objects in there:
mixedChoices.getItems().addAll("One", new Integer(2), new Double(3.0));
mixedChoices.getSelectionModel().selectedItemProperty().addListener(
(ObservableValue<? extends Object> ov, Object oldSelection, Object newSelection) ->
// compiler will only let me use Object here, but of course that makes sense, as I have no idea
// what object is selected....
System.out.println(newSelection.toString())
);但更好的方法是在同构的ChoiceBox中使用适当的对象类型。我会将这个示例实现为
ChoiceBox<Locale> languages = new ChoiceBox<>();
languages.getItems().addAll(Locale.ENGLISH, new Locale("es"), new Locale("pt"));
languages.setConverter(new StringConverter<Locale>() {
@Override
public String toString(Locale l) {
return l.getDisplayLanguage(l);
}
@Override
public Locale fromString(String language) {
// not really needed, but...
return Locale.forLanguageTag(language);
}
});
languages.getSelectionModel().selectedItemProperty().addListener(
(ObservableValue<? extends Locale> ov, Locale oldValue, Locale newValue) -> {
ResourceBundle rb = ResourceBundle.getBundle("messages", newValue);
theText.setText(rb.getString("greeting"));
});如果没有参数化,它将是
ChoiceBox languages = new ChoiceBox();
languages.getItems().addAll(Locale.ENGLISH, ...);但是现在编译器没有办法知道我们把Locale放到了选择框中,所以我们不得不向下转换:
languages.getSelectionModel().addListener(
(ObservableValue ov, Object oldChoice, Object newChoice) -> {
// hmm, I know I put Locales in there, even though the complier doesn't:
Locale languageChoice = (Locale) newChoice ;
// etc
});当然,现在的问题是,如果我犯了一个编码错误,并在ChoiceBox中放入了错误的内容,那么它只会在运行时被捕获。对于参数化版本,它是在编译时捕获的。这基本上就是在Swing中做事情的方式,也是一种非常传统的(pre JDK5)编码风格。
https://stackoverflow.com/questions/25729103
复制相似问题