在可观察的SimpleMapProperty中包装EnumMap

时间:2016-08-08 17:12:00

标签: java javafx listener observable

我需要将一个SimpleMapProperty添加到JavaFX服务类,但是如果我使用正确的方法,我不确定正确的语法。请注意,我并不是想让JavaFX服务看起来像Java Bean,我只需要知道如何从枚举ModuleType(可以是TYPEA或TYPEB)和相关的布尔标志来监听EnumMap的更新。从本质上讲,这可以被认为是一对包含在单个EnumMap中的看门狗定时器。

我无法理解如何添加底层的EnumMap条目(上面描述的每个ModuleType应该有2个)。

public class UDPListenerService  extends Service<Void> {
    // 'watchdog' property
    private final MapProperty<ModuleType, Boolean> watchdog;

    // 'watchdog' SimpleMapProperty bound property getter
    public ObservableMap<ModuleType, Boolean> getWatchdog() {
      return watchdog.get();
    }
    // 'watchdog' SimpleMapProperty bound property setter
    public void setWatchdog(ObservableMap<ModuleType, Boolean> aValue) {
        watchdog.set(aValue);
    }
    // 'watchdog' SimpleMapProperty bound property
    public MapProperty<ModuleType, Boolean> watchdogProperty() {
        return watchdog;
    }

    /**
     * Constructor
     */
    public UDPListenerService()
    {
        this.watchdog = new SimpleMapProperty<>(
            FXCollections.observableHashMap());
    }

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                updateMessage("Running...");
                while (!isCancelled()) {
                    try {
                        Thread.sleep(1000);
                        Platform.runLater(() -> {
                            try {
                                // update do some processing here
                                // . . .
                                // pet the watchdog
                                // setWatchdog
                                if (testforModuleType==ModuleType.TYPEA) {
                                    // please help with syntax
                                    setWatchdog(ModuleType.TYPEA, false);
                                } else {
                                    // please help with syntax
                                    setWatchdog(ModuleType.TYPEB, false);
                                }
                            } catch (StatusRuntimeException ex) {
                                // watchdog timed out - listener will
                                // update gui components
                                if (testforModuleType==ModuleType.TYPEA) {
                                    // please help with syntax
                                    setWatchdog(ModuleType.TYPEA, true);
                                } else {
                                    // please help with syntax
                                    setWatchdog(ModuleType.TYPEB, true);
                                }
                            }
                        });
                    } catch (InterruptedException ex) {}
                }
                updateMessage("Cancelled");
                return null;
            }
        };
    }
}

我使用这个类的方法是在JavaFX控制器类中,我在其中添加一个监听器,根据相关的布尔标志是真还是假来填充java gui元素。

1 个答案:

答案 0 :(得分:1)

通常只有readonly map属性用于这种行为,即只有一个getter的ObservableMap字段。只修改了地图的内容;分配初始地图后,不会为该字段分配新地图。

private final ObservableMap<ModuleType, Boolean> watchdog;

public ObservableMap<ModuleType, Boolean> getWatchdog() {
    return watchdog;
}

地图本身的修改方式与修改java.util.Map的方式相同,例如在这种情况下使用put方法。可以观察到变化,例如使用MapChangeListenerBindings.valueAt

此外EnumMap可用作Map的支持ObservableMap,但要执行此操作,需要使用observableMap方法代替observableHashMap方法

以下示例根据ObservableMap中的值随机选择/取消选择2个复选框的值。

private CheckBox checkBoxA;
private CheckBox checkBoxB;
private ObservableMap<ModuleType, Boolean> map;

@Override
public void start(Stage primaryStage) {
    checkBoxA = new CheckBox("type A");
    checkBoxB = new CheckBox("type B");

    map = FXCollections.observableMap(new EnumMap<>(ModuleType.class));

    initMapListeners();

    Thread t = new Thread(() -> {
        Random random = new Random();
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
            }
            boolean b1 = random.nextBoolean();
            boolean b2 = random.nextBoolean();
            Platform.runLater(() -> {
                map.put(ModuleType.TYPEA, b1);
                map.put(ModuleType.TYPEB, b2);
            });
        }
    });
    t.setDaemon(true);
    t.start();

    Scene scene = new Scene(new VBox(10, checkBoxA, checkBoxB));

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

以下initMapListeners()的实现都会根据地图值设置CheckBox.selected状态。

private void initMapListeners() {
    checkBoxA.selectedProperty().bind(Bindings.valueAt(map, ModuleType.TYPEA));
    checkBoxB.selectedProperty().bind(Bindings.valueAt(map, ModuleType.TYPEB));
}
private void initMapListeners() {
    map.addListener((MapChangeListener.Change<? extends ModuleType, ? extends Boolean> change) -> {
        if (change.wasAdded()) {
            if (change.getKey() == ModuleType.TYPEA) {
                checkBoxA.setSelected(change.getValueAdded());
            } else if (change.getKey() == ModuleType.TYPEB) {
                checkBoxB.setSelected(change.getValueAdded());
            }
        }
    });
}
相关问题