状态更改时更新fxml标记

时间:2020-03-08 15:09:46

标签: javafx fxml

我想创建某种“安全性” fxml标记,以根据某种SecurityManager类的状态禁用/使其子代不可见。

我遇到的困难如下。当SecurityManager类的状态更改时,我希望所有securityTag都更新其可见属性。当然,我可以每次调用标签构造函数时,将所有SecurityTag节点添加到静态列表中,并在SecurityManger类更改状态时在其上循环。但是,如果安全标记节点从父节点移除,该怎么办?如何在列表中删除它?也许只有一种更好的全面方法来解决这个问题?

public class SecurityTag extends Pane {

    public Security() {
        super();
        this.setVisible(false);
    }

}
public class SecurityManager {

    private boolean authorized;

    public SecurityManager() {
        this.authorized = false;
    }

    public void login() {
        this.authorized = true;
    }

    public void logout() {
        this.authorized = false;
    }

    public boolean isAuthorized() {
        return authorized;
    }

}

1 个答案:

答案 0 :(得分:0)

最简单的方法是将authorized中的SecurityManager属性设置为JavaFX属性:

package org.jamesd.examples.security;

import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;

public class SecurityManager {

    private final ReadOnlyBooleanWrapper authorized ;

    public SecurityManager() {
        this.authorized = new ReadOnlyBooleanWrapper(false) ;
    }



    public void login() {
        this.authorized.set(true);
    }

    public void logout() {
        this.authorized.set(false);
    }

    public ReadOnlyBooleanProperty authorizedProperty() {
        return authorized.getReadOnlyProperty();
    }

    public boolean isAuthorized() {
        return authorizedProperty().get();
    }

}

现在,您只需将相关属性绑定到authorized的{​​{1}}属性即可。根据要绑定的属性,可以直接在FXML或控制器中执行此操作。您可以通过将SecurityManager实例放置在SecurityManager的{​​{1}}中来使其对FXML文件可用,并通过将其作为参数传递给控制器​​来使其对控制器可用。构造函数,并在FXMLLoader上手动设置控制器(即不使用namespace属性)。

这是示例FXML文件。注意“ Privileged Action”按钮如何通过

将其可见性绑定到安全管理器
fx:controller

您也可以

FXMLLoader

如果您只想禁用它。

visible = "${securityManager.authorized}" 

这里是控制器。使用比FXML中更复杂的绑定,将标签的文本绑定到安全管理器的状态:

disable = "${ !securityManager.authorized}" 

最后,这是所有组件的组装方式:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets ?>
<?import javafx.scene.layout.BorderPane ?>
<?import javafx.scene.layout.VBox ?>
<?import javafx.scene.control.Button ?>
<?import javafx.scene.control.Label ?>

<BorderPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
    <top>
        <Label fx:id = "securityStatus"></Label>
    </top>
    <center>
        <VBox spacing="5" fillWidth="true">
            <Button text="Regular Action" maxWidth="Infinity"></Button>
            <Button text="Privileged Action" visible = "${securityManager.authorized}" maxWidth="Infinity"></Button>

            <padding>
                <Insets top="5" left="5" right="5" bottom="5"/>
            </padding>
        </VBox>
    </center>
    <left>
        <VBox spacing="5" fillWidth="true">
            <Button text="login" onAction="#login" maxWidth="Infinity"/>
            <Button text="logout" onAction="#logout" maxWidth="Infinity"/>

            <padding>
                <Insets top="5" left="5" right="5" bottom="5"/>
            </padding>
        </VBox>
    </left>
</BorderPane>

请注意,这种方法避免了JavaFX节点的任何不必要的子类化(例如package org.jamesd.examples.security; import javafx.beans.binding.Bindings; import javafx.fxml.FXML; import javafx.scene.control.Label; public class SecurityController { private final SecurityManager securityManager ; @FXML private Label securityStatus ; public SecurityController(SecurityManager securityManager) { this.securityManager = securityManager ; } public void initialize() { securityStatus.textProperty().bind(Bindings .when(securityManager.authorizedProperty()) .then("Logged In") .otherwise("Logged Out") ); } @FXML private void login() { securityManager.login(); } @FXML private void logout() { securityManager.logout(); } } ),这可能会导致问题(例如,您可能希望将与安全相关的节点放置在现有的布局窗格中,这使得更难以使用标准布局。


如果按照注释中的建议,您希望package org.jamesd.examples.security; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.stage.Stage; public class SecurityApp extends Application { @Override public void start(Stage primaryStage) throws Exception { SecurityManager securityManager = new SecurityManager(); FXMLLoader loader = new FXMLLoader(getClass().getResource("SecurityExample.fxml")); loader.getNamespace().put("securityManager", securityManager); loader.setController(new SecurityController(securityManager)); Scene scene = new Scene(loader.load()); primaryStage.setScene(scene); primaryStage.show(); } public static void main(String[] args) { Application.launch(args); } } 类与JavaFX(以及一般来说是台式机Java)无关,则可以为使用JavaFX属性的UI创建一个委托,并进行安排以便在更新“真实”安全管理器时对其进行更新。

例如这是一个实现经典“侦听器”模式的Pane

SecurityManager

SecurityManager

请注意,这些对于任何视图技术都是完全不可知的。

现在您可以创建“ UI安全管理器委托”:

package org.jamesd.examples.security;

@FunctionalInterface
public interface AuthorizationListener {
    void authorizationChanged(boolean newStatus);
}

最后使用来更新UI代码

package org.jamesd.examples.security;

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

public class SecurityManager  {

    private boolean authorized ;
    private final List<AuthorizationListener> listeners ;

    public SecurityManager() {
        this.listeners = new ArrayList<>();
    }

    public void login() {
        setAuthorized(true);
    }

    public void logout() {
        setAuthorized(false);
    }

    public void addListener(AuthorizationListener listener) {
        listeners.add(listener);
    }

    public void removeListener(AuthorizationListener listener) {
        listeners.remove(listener);
    }

    public boolean isAuthorized() {
        return authorized;
    }

    private void setAuthorized(boolean authorized) {
        if (! this.authorized == authorized) {
            this.authorized = authorized ;
            listeners.forEach(l -> l.authorizationChanged(authorized));
        }
    }

}

package org.jamesd.examples.security;

import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;

public class UISecurityDelegate  {

    private final ReadOnlyBooleanWrapper authorized ;

    private final SecurityManager manager ;

    public UISecurityDelegate(SecurityManager manager) {
        this.manager = manager ;
        this.authorized = new ReadOnlyBooleanWrapper(manager.isAuthorized()) ;
        manager.addListener(authorized::set);
    }

    public void login() {
        manager.login();
    }
    public void logout() {
        manager.logout();
    }

    public ReadOnlyBooleanProperty authorizedProperty() {
        return authorized.getReadOnlyProperty();
    }

    public boolean isAuthorized() {
        return authorizedProperty().get();
    }

}
相关问题