java - 将 EnumMap 包装在可观察的 SimpleMapProperty 中

标签 java javafx listener observable

我需要将 SimpleMapProperty 添加到 JavaFX 服务类,但我不确定是否使用正确的方法,语法是否正确。请注意,我并不是想让 JavaFX 服务看起来像 Java Bean,我只需要知道如何从枚举 ModuleType(可以是 TYPEA 或 TYPEB)和关联的 boolean 标志监听 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 Controller 类中添加一个监听器,该监听器根据关联的 boolean 标志是 true 还是 false 来填充 java gui 元素。

最佳答案

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

private final ObservableMap<ModuleType, Boolean> watchdog;

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

map 本身的修改方式与修改java.util.Map的方式相同,例如在本例中使用 put 方法。可以观察到变化,例如使用 MapChangeListenerBindings.valueAt

此外,EnumMap 可以用作 ObservableMap 的支持 Map,但要做到这一点需要 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() 实现都会根据 map 值设置 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());
            }
        }
    });
}

关于java - 将 EnumMap 包装在可观察的 SimpleMapProperty 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38834966/

相关文章:

java - Java::server 中的客户端服务器程序不从文件中逐行读取文本

java - 需要重新设置oracle中sequence的值

绑定(bind)到 GraphicPropety 的 JavaFX ImageView 未显示在多个 View 上

servlets - 哪个Servlet Listener不需要在web.xml中配置?

javascript - 如何为遵循类似 ID 结构的所有 HTML 对象创建更改监听器?

java - 在 GAE 中实现一致的响应时间?

Java:允许重复的排序列表/集合

java - 对象数组到文本区域

java - 如何在处理时禁用按钮

java - 带有事件监听器的 Android 多线程