Самый простой способ сделать это - сделать свойство 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
из SecurityManager
. В зависимости от свойства, которое вы связываете, вы можете сделать это непосредственно в F XML или в контроллере. Вы можете сделать экземпляр SecurityManager
доступным для файла F XML, поместив его в namespace
FXMLLoader
и сделать его доступным для контроллера, просто передав его в качестве параметра конструктору контроллера, и установка контроллера вручную (т.е. без использования атрибута fx:controller
) для FXMLLoader
.
Вот пример файла F XML. Обратите внимание, как кнопка «Привилегированное действие» связывает ее видимость с менеджером безопасности с помощью
visible = "${securityManager.authorized}"
. Вы также можете сделать
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>
Вот контроллер. Текст метки привязан к состоянию диспетчера безопасности с использованием более сложной привязки, чем это может быть достигнуто в F XML:
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 (например, Pane
), что может привести к проблемам (например, вы можете разместить зависимые от безопасности узлы в существующей панели макета, и это делает более сложным использование стандартных макетов).
Если, как предлагается в комментариях, вы хотите, чтобы класс SecurityManager
был агностирован c по отношению к JavaFX (и, вероятно, настольный Java) в общем), вы можете просто создать делегат для пользовательского интерфейса, который использует свойства JavaFX, и организовать его обновление при обновлении «реального» менеджера безопасности.
Например, вот SecurityManager
, который реализует Классическая схема «слушателя»:
package org.jamesd.examples.security;
@FunctionalInterface
public interface AuthorizationListener {
void authorizationChanged(boolean newStatus);
}
и
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));
}
}
}
Обратите внимание, что это абсолютно агности c по отношению к любой технологии просмотра.
Теперь вы можете a создать «делегат администратора безопасности интерфейса пользователя»:
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();
}
}
и, наконец, обновить код интерфейса пользователя с помощью
package org.jamesd.examples.security;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class SecurityController {
private final UISecurityDelegate securityManager ;
@FXML
private Label securityStatus ;
public SecurityController(UISecurityDelegate 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 {
// probably created by data or service layer, etc:
SecurityManager securityManager = new SecurityManager();
UISecurityDelegate securityDelegate = new UISecurityDelegate(securityManager) ;
FXMLLoader loader = new FXMLLoader(getClass().getResource("SecurityExample.fxml"));
loader.getNamespace().put("securityManager", securityDelegate);
loader.setController(new SecurityController(securityDelegate));
Scene scene = new Scene(loader.load());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}