基于其值的属性使ObjectProperty无效

时间:2017-02-18 14:02:25

标签: javafx-8

我的情况是我有PropertyList<ParentObject>ParentObject有一个ObjectProperty<ChildObject>,其中包含一组属性。我想强制ChildObject在某些属性发生变化时被标记为无效。这样我就可以提取它们了。

我尝试使用SimpleListProperty提取器参数和绑定直接提取它们,但它没有用。

我要求做一些我不应该做的事吗?干净的方法是什么?

这是一个有点人为的例子。目标是让管理员计数正确显示用户具有管理员角色的ApplicationInstances数量。

public class MCVE extends Application {


    ObjectProperty<Model> model = new SimpleObjectProperty<>(this, "model", new Model());
    private static ObservableList<UserRole> userRoles = FXCollections.observableList(Arrays.asList(UserRole.values()));
    private static StringConverter<UserRole> userRoleStringConverter = new StringConverter<UserRole>() {
        @Override
        public String toString(UserRole object) {
            return object.getDescription();
        }

        @Override
        public UserRole fromString(String string) {
            return UserRole.get(string);
        }
    };

    @Override
    public void start(Stage primaryStage) throws Exception {
        User fooUser = new User("Foo", UserRole.UNAUTHENTICATED);
        User barUser = new User("Bar", UserRole.ADMINISTRATOR);
        ApplicationInstance changeableApplicationInstance = new ApplicationInstance(fooUser, "1.0.1");
        model.get().getApplicationInstances().add(new ApplicationInstance(new User("John", UserRole.DATA_ANALYSIS_GUY), "1.0.0"));
        model.get().getApplicationInstances().add(new ApplicationInstance(new User("Damien", UserRole.DATA_ANALYSIS_GUY, UserRole.DATA_INPUT_GUY), "1.0.0"));
        model.get().getApplicationInstances().add(changeableApplicationInstance);

        VBox root = new VBox(10);
        TableView<ApplicationInstance> applicationInstanceTableView = new TableView<>();
        TableColumn<ApplicationInstance, String> versionColumn = new TableColumn<>("Application version");
        versionColumn.setCellValueFactory(param -> param.getValue().versionProperty());
        TableColumn userRoleTableColumn = new TableColumn<>("User");
        TableColumn<ApplicationInstance, ObservableSet<UserRole>> userRoleColumn = new TableColumn<>("User role");
        TableColumn<ApplicationInstance, String> userNameColumn = new TableColumn<>("User name");

        userNameColumn.setCellValueFactory(param -> EasyBind.monadic(param.getValue().userProperty()).selectProperty(User::nameProperty));
        userRoleColumn.setCellValueFactory(param -> EasyBind.monadic(param.getValue().userProperty()).selectProperty(User::userRolesProperty));
        userRoleColumn.setCellFactory(param -> new TableCell<ApplicationInstance, ObservableSet<UserRole>>() {

            @Override
            protected void updateItem(ObservableSet<UserRole> item, boolean empty) {
                super.updateItem(item, empty);
                if (item == null || empty) {
                    setGraphic(null);
                } else {
                    setText(getItem().stream().map(UserRole::getDescription).collect(Collectors.joining(", ")));
                }
            }
        });
        userRoleColumn.setEditable(true);

        userRoleTableColumn.getColumns().addAll(userNameColumn, userRoleColumn);
        applicationInstanceTableView.getColumns().addAll(versionColumn, userRoleTableColumn);
        applicationInstanceTableView.itemsProperty().bind(EasyBind.monadic(model).map(Model::applicationInstancesProperty));

        // Assume this action comes from somewhere else in the system
        Button changeUserRoleButton = new Button("Change role of user Foo");
        Random randomUserRole = new Random();
        changeUserRoleButton.setOnAction(event -> {
            int randomPos = randomUserRole.nextInt(UserRole.values().length);
            fooUser.getUserRoles().clear();
            fooUser.getUserRoles().add(UserRole.values()[randomPos]);
        });

        Button changeUserButton = new Button("Change user of 1.0.1 version instance");
        changeUserButton.setOnAction(event -> {
            if (changeableApplicationInstance.getUser() == fooUser) {
                changeableApplicationInstance.setUser(barUser);
            } else {
                changeableApplicationInstance.setUser(fooUser);
            }
        });

        Text onlineAdmins = new Text();
        onlineAdmins.textProperty().bind(EasyBind.monadic(model).selectProperty(Model::onlineAdminsProperty).map(number -> "Online adminstrators: "+number.toString()));

        root.getChildren().addAll(applicationInstanceTableView, changeUserRoleButton, changeUserButton, onlineAdmins);
        Scene scene = new Scene(root, 800, 600);
        root.prefWidthProperty().bind(scene.widthProperty());
        primaryStage.setTitle("MCVE");
        primaryStage.setScene(scene);
        primaryStage.initStyle(StageStyle.DECORATED);
        primaryStage.show();
    }

    public static void main(String... args) {
        launch(args);
    }

    private class Model {
        private ListProperty<ApplicationInstance> applicationInstances = new SimpleListProperty<>(this, "applicationInstances", FXCollections.observableArrayList(
                (Callback<ApplicationInstance, Observable[]>) param -> new Observable[]{
                        param.versionProperty(),
                }
        ));

        private IntegerProperty onlineAdmins = new SimpleIntegerProperty(this,"onlineAdmins",0);
        private FilteredList<ApplicationInstance> adminInstances;

        public Model() {
            adminInstances = applicationInstances.filtered(applicationInstance -> (applicationInstance.getUser().getUserRoles().contains(UserRole.ADMINISTRATOR)));
            adminInstances.addListener(new InvalidationListener() {
                @Override
                public void invalidated(Observable observable) {
                    onlineAdmins.set(adminInstances.size());
                }
            });
        }

        public ObservableList<ApplicationInstance> getApplicationInstances() {
            return applicationInstances.get();
        }

        public ListProperty<ApplicationInstance> applicationInstancesProperty() {
            return applicationInstances;
        }

        public void setApplicationInstances(ObservableList<ApplicationInstance> applicationInstances) {
            this.applicationInstances.set(applicationInstances);
        }

        public int getOnlineAdmins() {
            return onlineAdmins.get();
        }

        public IntegerProperty onlineAdminsProperty() {
            return onlineAdmins;
        }
    }

    private class ApplicationInstance {
        ObjectProperty<User> user = new SimpleObjectProperty<>(this, "user");
        StringProperty version = new SimpleStringProperty(this, "version");

        public ApplicationInstance() {
        }

        public ApplicationInstance(User user, String version) {
            this.user.set(user);
            this.version.set(version);
        }

        public User getUser() {
            return user.get();
        }

        public ObjectProperty<User> userProperty() {
            return user;
        }

        public void setUser(User user) {
            this.user.set(user);
        }

        public String getVersion() {
            return version.get();
        }

        public StringProperty versionProperty() {
            return version;
        }

        public void setVersion(String version) {
            this.version.set(version);
        }
    }

    public class User {
        SetProperty<UserRole> userRoles = new SimpleSetProperty<>(this, "userRoles", FXCollections.observableSet());
        StringProperty name = new SimpleStringProperty(this, "name");

        public User() {
        }

        public User(String name, UserRole... userRoles) {
            this.name.set(name);
            Arrays.stream(userRoles).forEach(userRole -> this.userRoles.add(userRole));
        }

        public ObservableSet<UserRole> getUserRoles() {
            return userRoles.get();
        }

        public SetProperty<UserRole> userRolesProperty() {
            return userRoles;
        }

        public void setUserRoles(ObservableSet<UserRole> userRoles) {
            this.userRoles.set(userRoles);
        }

        public String getName() {
            return name.get();
        }

        public StringProperty nameProperty() {
            return name;
        }

        public void setName(String name) {
            this.name.set(name);
        }
    }

    //  UserRights as enums for shortness
    public enum UserRole {
        DATA_ANALYSIS_GUY("Data analysis guy"), ADMINISTRATOR("Administrator"), SOME_ROLE("Some role"),
        DATA_INPUT_GUY("Data input guy"), UNAUTHENTICATED("Unauthenticated user");
        private String description;

        private static Map<String, UserRole> stringUserRightMap = new HashMap<>();

        static {
            for (UserRole userRole : UserRole.values()) {
                stringUserRightMap.put(userRole.description, userRole);
            }
        }

        UserRole(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }

        public static UserRole get(String description) {
            return stringUserRightMap.get(description);
        }
    }
}

编辑:似乎没有对此的支持。使用ObservableProperty时,直接在属性上绑定/侦听的标准方法只有在您不将它们视为对象(它们所属的bean)的更改时才有效。更有趣的是,ListProperty获得了有一个提取器而不是SetPropertyMapProperty的处理方式。我真的很想知道是否有一些建筑或OOP的原因。

0 个答案:

没有答案