javaFX中是不是有等效的枚举属性类型?

Posted

技术标签:

【中文标题】javaFX中是不是有等效的枚举属性类型?【英文标题】:Is there an equvalent of enum property type in javaFX?javaFX中是否有等效的枚举属性类型? 【发布时间】:2017-03-12 08:44:25 【问题描述】:

我想观察一些 java bean 类的某些字段的变化。 该字段为枚举类型。 要绑定字段和相应的 ui 控件,我将使用 PropertyChangeListener,如 here 所述 但似乎 javaFX 没有等效的枚举属性类型。类似javafx.beans.property.EnumProperty 我尝试改用StringPropertyObjectProperty,但它不起作用。

更新添加了一个sscce

Observable.java

package sample;

    import java.beans.PropertyChangeListener;
    import java.beans.PropertyChangeSupport;

    public class Observable 

        protected PropertyChangeSupport propertyChangeSupport = null;

        public Observable() 

        public void setObservableObject (Observable observable) 
            propertyChangeSupport = new PropertyChangeSupport(observable);
        

        public void addPropertyChangeListener(PropertyChangeListener listener)
            System.out.println("added PropertyChangeListener");
            propertyChangeSupport.addPropertyChangeListener(listener);
        
    

Item.java

package sample;


    public class Item extends Observable 

        public enum State 
            INIT, STARTED
        

        private String name;
        private State state = State.INIT;

        public Item() 
            super();
            super.setObservableObject(this);
        

        public Item(String name, State state) 
            this();
            setName(name);
            setState(state);
        

        public String getName() 
            return name;
        

        public void setName(String name) 
            this.name = name;
        

        public State getState() 
            return state;
        

        public void setState(State state) 
            State oldState = this.state;
            this.state = state;
            System.out.println(String.format("%s: change state from %s to %s",name,oldState.name(),state));
            propertyChangeSupport.firePropertyChange("state", oldState, state);
        


    

Main.java

package sample;

    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;

    public class Main extends Application 

        @Override
        public void start(Stage primaryStage) throws Exception 
            Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
            primaryStage.setTitle("Item View");
            primaryStage.setScene(new Scene(root, 200, 100));
            primaryStage.show();
        


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

sample.fxml

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

    <?import javafx.scene.control.Button?>
    <?import javafx.scene.control.CheckBox?>
    <?import javafx.scene.control.ComboBox?>
    <?import javafx.scene.control.Label?>
    <?import javafx.scene.layout.AnchorPane?>

    <AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="108.0" prefWidth="225.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
             <children>
                <Label layoutX="14.0" layoutY="14.0" text="show item" />
                <ComboBox fx:id="cbxItemsSelector" layoutX="14.0" layoutY="31.0" prefWidth="150.0" />
                <Button fx:id="btnChangeState" layoutX="14.0" layoutY="65.0" mnemonicParsing="false" onAction="#changeItemState" prefHeight="25.0" prefWidth="85.0" text="change state" />
             </children>
    </AnchorPane>

Controller.java

package sample;

    import javafx.beans.Observable;
    import javafx.beans.property.adapter.JavaBeanObjectPropertyBuilder;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.fxml.FXML;
    import javafx.scene.control.ComboBox;
    import javafx.scene.control.ListCell;
    import javafx.scene.control.ListView;
    import javafx.util.Callback;


    import java.util.ArrayList;
    import java.util.List;

    public class Controller 

        @FXML
        private ComboBox<Item> cbxItemsSelector;

        private ObservableList<Item> items;

        public void initialize() 
            loadItems();
            customizeSelectorCellView();
        

        private void loadItems() 
            List<Item> itemsList = new ArrayList<>();
            itemsList.add(new Item("first item", Item.State.INIT));
            itemsList.add(new Item("second item", Item.State.INIT));

            items = FXCollections.observableList(itemsList, item -> 
                try 
                    return new Observable[]
                            new JavaBeanObjectPropertyBuilder().bean(item).name("state").build()
                    ;
                 catch (NoSuchMethodException e) 
                    e.printStackTrace();
                    return new Observable[];
                
            );

            cbxItemsSelector.setItems(items);
        

        private void customizeSelectorCellView() 


            cbxItemsSelector.setButtonCell(new ListCell<Item>() 
                @Override
                protected void updateItem(Item item, boolean empty) 
                    super.updateItem(item, empty);
                    if (empty) 
                        setText("");
                     else 
                        setText(item.getName());
                    
                
            );
            cbxItemsSelector.setCellFactory(
                    new Callback<ListView<Item>, ListCell<Item>>() 
                        @Override
                        public ListCell<Item> call(ListView<Item> p) 
                            ListCell cell = new ListCell<Item>() 
                                @Override
                                protected void updateItem(Item item, boolean empty) 
                                    super.updateItem(item, empty);
                                    if (empty) 
                                        setText("");
                                     else 
                                        System.out.println(String.format("update %s",item.getName()));
                                        setText(String.format("name: %s\n state: %s\n", item.getName(), item.getState().name()));
                                    
                                
                            ;
                            return cell;
                        
                    
            );
        

        @FXML
        public void changeItemState() 
            Item selectedItem = cbxItemsSelector.getSelectionModel().getSelectedItem();
            if (selectedItem == null) return;

            selectedItem.setState(Item.State.STARTED);

        

    

所以,当我现在运行它时,我会得到下一个输出:

first item: change state from INIT to INIT
second item: change state from INIT to INIT
added PropertyChangeListener
added PropertyChangeListener
update first item
update second item
update first item
update second item
update first item
update first item
update second item
first item: change state from INIT to STARTED
second item: change state from INIT to STARTED
Process finished with exit code 0

如您所见,更新项目在项目状态更改后不会被调用。 我使用:jdk中包含的jre 1.8.0_91-b15 x64

【问题讨论】:

对象属性将起作用。 哦。是的。我发现了问题。我用FxControls Validation 控制。由于某种原因,如果启用验证,它将无法工作 @James_D 嗯,实际上验证不是问题的原因。我把它删掉了,反正也看到了同样的问题。但是奇怪的事情发生了。昨天这个例子奏效了,我看到了更新的状态。今天它不起作用。我没有改变任何东西。我刚刚添加了一个示例。请看一下。你能重现这个问题吗? 【参考方案1】:

@rvit34 - 或者重命名sample.Observable(我重命名为MyObservable),在sample.Item 中明确地import sample.Observable;,或者更改行:

public class Item extends Observable 

到:

public class Item extends sample.Observable 

它应该可以解决您的问题。以下是:

1) 修改后的示例代码产生的输出

2) 对原始源文件所做的所有更改(为简洁起见,我只包含更改而不是整个示例代码)

3) 解释导致问题的原因以及避免未来类似性质问题的技术。

我的输出:

run:
first item: change state from INIT to INIT...
...
first item: change state from INIT to STARTED
update first item
second item: change state from INIT to STARTED
update second item
first item: change state from STARTED to INIT
update first item
second item: change state from STARTED to INIT
update second item
BUILD SUCCESSFUL (total time: 32 seconds)

MyObservable.java(从 Observable.java 重命名)

public class MyObservable 
...

Item.java

public class Item extends MyObservable 
    ...
    public MyObservable() 

    public void setObservableObject (MyObservable observable) 
        ...
    

Controller.java(不需要让它工作。修改为循环状态,而不是仅仅设置为 STARTED)

public void changeItemState() 
        Item selectedItem = cbxItemsSelector.getSelectionModel().getSelectedItem();
        if (selectedItem != null) 

            switch (selectedItem.getState()) 
                case STARTED:
                    selectedItem.setState(Item.State.INIT);
                    break;
                case INIT:
                    selectedItem.setState(Item.State.STARTED);
                    break;
                default:
                    break;
            
        

    

问题(以及发生适当行为的机会)来自命名空间冲突。

sample.Item 继承自 sample.Observable。因为这两个类都是包sample 的成员,所以当您声明Item extends Observable 时,您既不必导入sample.Observable,也不必明确声明您的意思是sample.Observable,这通常不会成为问题。因为,您在Main 中使用javafx.beans.Observable,它似乎混淆了JRE(它实际上不应该,这可能是您正在发现的JVM 中的一个错误)。随机成功运行可能是由于系统负载或其他一些随机环境变量或条件导致 jvm 挂起加载 javafx.beans.Observable 直到将 Item 注册为 sample.Observable 或 sample.Observable 类型的对象之后在启动时被加载到内存中。

编辑 - 上面实际上并没有回答帖子标题中提出的问题,但它确实解决了帖子正文中讨论的问题。要回答标题问题,SetProperty&lt;E&gt; 看起来非常适合用作枚举属性。没有尝试在提供的示例代码中实现这一点,可能不会,但我将使用我目前正在处理的项目中的一个工作示例重新编辑,这让我寻找标题问题的答案。

【讨论】:

以上是关于javaFX中是不是有等效的枚举属性类型?的主要内容,如果未能解决你的问题,请参考以下文章

python枚举是不是有等效的Scala?

JavaFX SwingWorker 等价物?

您是不是在 WCF Web 服务中使用枚举类型?

默认(类型)的编程等效项

std::list 模板在其实例类型中是不是需要复制构造函数(或等效项)?

如何通过传入枚举值和属性类型来获取枚举的自定义属性?