繁体   English   中英

有没有办法在JAVAFX上实现像“呈现”这样的属性?

[英]Is there a way to implement a property like “rendered” on JAVAFX?

如果条件满足,有没有办法只在Javafx中“渲染”一个组件? 我感兴趣的是做一个具有不同角色的用户界面,如果角色允许,只需添加一个组件,我也想继续使用FXML。 我没有读过类似的东西。

绑定可见性

将组件的visible属性 绑定BooleanExpression,表示应该可见的条件。

FXML可以进行绑定 ,但请注意,从JavaFX 2.2开始“目前仅支持解析为属性值或页面变量的简单表达式。将来可能会添加对涉及布尔值或其他运算符的更复杂表达式的支持。”

如果不在FXML中绑定,则可以使用JavaFX API绑定Java代码。

node.visibleProperty().bind(conditionProperty);

如果您不希望不可见属性占用布局空间,请先将托管属性绑定到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这样的东西感兴趣,所以我创建了一个小框架来处理基于角色的FXML UI 它可能有一些性能增强,并为定义基于角色的控制器添加一些便利定义以及FXML中角色定义的缩写,但它似乎确实在原理上工作并演示了一种基本方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM