如果条件满足,有没有办法只在Javafx中“渲染”一个组件? 我感兴趣的是用不同的角色做一个用户界面,然后添加 如果角色允许的话,我也希望继续使用FXML。 我还没有读过类似的东西。
答案 0 :(得分:14)
绑定可见性
Bind您组件的visible property到BooleanExpression,表示应该可见的条件。
FXML可以执行binding,但请注意,从JavaFX 2.2开始“目前仅支持解析为属性值或页面变量的简单表达式。可以添加对包含布尔值或其他运算符的更复杂表达式的支持未来“。
如果未在FXML中绑定,则可以使用JavaFX API绑定Java代码。
node.visibleProperty().bind(conditionProperty);
如果您不希望不可见属性占用布局空间,请先将managed property绑定到visible属性。
node.managedProperty().bind(node.visibleProperty());
交替更改更改侦听器中的可见性
请注意,为基于完整角色的系统设置绑定非常复杂,因此对于此类任务,最好使用更改侦听器并使用Java编写逻辑的一部分,而不是尝试在FXML中执行所有操作。您仍然可以在FXML中设计UI,但是您可以在控制器中添加一些代码来管理哪些项目对于哪个角色是可见的。
基于示例角色的展示
以下是使用Java API的基于角色的解决方案。
解决方案根据所选角色显示不同的标记图片。
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.collections.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import java.util.*;
enum Role { father, son, mother, daughter, brother, sister }
class RoleManager {
private final Map<Node, List<Role>> nodeRoles = new HashMap<>();
private ObservableList<Role> activeRoles;
public final ListChangeListener<Role> ACTIVE_ROLE_LISTENER = new ListChangeListener<Role>() {
@Override
public void onChanged(Change<? extends Role> c) {
showActiveNodes();
}
};
public void setActiveRoles(ObservableList<Role> activeRoles) {
if (this.activeRoles != null) {
this.activeRoles.removeListener(ACTIVE_ROLE_LISTENER);
}
this.activeRoles = activeRoles;
this.activeRoles.addListener(ACTIVE_ROLE_LISTENER);
}
public void showActiveNodes() {
for (Node node : nodeRoles.keySet()) {
node.setVisible(isActive(node));
}
}
public void assignRole(Node node, Role... roles) {
nodeRoles.put(node, Arrays.asList(roles));
}
private boolean isActive(Node node) {
if (activeRoles == null) {
return false;
}
for (Role role: nodeRoles.get(node)) {
if (activeRoles.contains(role)) {
return true;
}
}
return false;
}
}
public class RoleVisibility extends Application {
private RoleManager roleManager = new RoleManager();
@Override
public void start(Stage stage) {
VBox layout = new VBox(10);
layout.getChildren().setAll(
getRoleChooser(),
createContent()
);
layout.setStyle("-fx-padding: 10px; -fx-background-color: cornsilk;");
roleManager.showActiveNodes();
stage.setTitle("Role Selector");
stage.setScene(new Scene(layout));
stage.show();
}
private Node getRoleChooser() {
ObservableList<Role> activeRoles = FXCollections.observableArrayList();
VBox roleChooser = new VBox(10);
for (final Role role: Role.values()) {
CheckBox checkBox = new CheckBox(role.toString());
checkBox.selectedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean wasSelected, Boolean isSelected) {
if (isSelected) {
activeRoles.add(role);
} else {
activeRoles.remove(role);
}
}
});
roleChooser.getChildren().add(checkBox);
}
roleManager.setActiveRoles(
activeRoles
);
return roleChooser;
}
private Pane createContent() {
HBox content = new HBox(10);
// icon license:
//License: Free for non-commercial use.
//Commercial usage: Not allowed
//The products or characters depicted in these icons are © by Lucasfilm Ltd.
content.getChildren().addAll(
createLabel("Darth Vader", "Vader-03-icon.png", Role.father),
createLabel("Queen Amidala", "Padme-Amidala-icon.png", Role.mother),
createLabel("Luke Skywalker", "Luke-Skywalker-01-icon.png", Role.brother, Role.son),
createLabel("Princess Leia", "Leia-icon.png", Role.daughter, Role.sister)
);
return content;
}
private Label createLabel(String text, String graphic, Role... roles) {
Label label = new Label(
text,
new ImageView(
new Image(
"http://icons.iconarchive.com/icons/jonathan-rey/star-wars-characters/128/" + graphic
)
)
);
label.setContentDisplay(ContentDisplay.TOP);
roleManager.assignRole(label, roles);
return label;
}
public static void main(String[] args) {
launch(args);
}
}
基于FXML的解决方案
我对使用FXML这样的东西感兴趣,所以我创建了一个small framework to handle role based FXML UIs。它可能有一些性能增强,并为定义基于角色的控制器添加一些便利定义以及FXML中角色定义的缩写,但它似乎在原则上起作用并演示了一种基本方法。