【问题标题】:Styling of subelement of RadioButton in JavaFX using CSS使用 CSS 对 JavaFX 中 RadioButton 的子元素进行样式设置
【发布时间】:2016-02-08 20:28:36
【问题描述】:

我正在尝试使用 CSS 更改 JavaFX 中 RadioButton 的外观,但遇到了问题。 根据 JavaFX CSS 参考指南元素结构由子元素组成:

   radio — Region
      dot — Region
   label — Label

在 modena.css 中风格化的子元素无线电:

.radio-button > .radio,
.radio-button:focused > .radio  {
   -fx-background-radius: 1.0em;
   -fx-padding: 0.333333em;
}

通过覆盖这些样式类可以配置子元素的外观。 Sub .dot 也风格化。 但是...如果我尝试将代码添加到子元素标签,例如:

.radio-button > .label,
.radio-button:focused > .label {
   -fx-background-color: rgb(200,200,200);
}

...什么也没发生。 如何风格化这个子? 有没有办法查看元素的内部结构和可以更改这些元素的 css 属性(JavaFX CSS 参考指南除外)?

【问题讨论】:

    标签: java css javafx javafx-8


    【解决方案1】:

    问题的第二部分我会自己回答。为了显示元素 JavaFX 的结构和属性,我编写了该实用程序。也许有人会觉得它很有用。

    public class CssMetaDataExtractor extends Application {
    private Stage primaryStageLink;
    private Scene primaryScene;
    private SplitPane rootNode;
    private Group group;
    private TreeView<String> structureTV;
    private Component structureRoot;
    private TreeView<String> nodePropertiesTV;
    private TreeItem<String> nodePropertiesRoot;
    private TreeTableView<CMDComponent> cssPropertiesTV;
    private TreeItem<CMDComponent> cssPropertiesRoot;
    
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) {
        primaryStageLink = primaryStage;
        createContent();
        primaryScene.getStylesheets().add( CssMetaDataExtractor.class.getResource("test.css").toExternalForm() );
        /* Create and tune your element here... */
        ProgressBar pb = new ProgressBar();
        /* ...and add element here... */
        processElement( pb );
    }
    
    private void processElement(Node node) {
        group.getChildren().add(node);
        primaryStageLink.show();
        if ( node instanceof Parent ) {
            extractCssMetaData((Parent)node, null);
            node.addEventHandler(Event.ANY, (Event event) -> {
                Component selected = (Component)structureTV.getSelectionModel().selectedItemProperty().getValue();
                showCssProperties( selected );
                showNodeProperties( selected );
            });
        }
    }
    private void extractCssMetaData(Parent node, Component parent) {
        Component currentParent = parent;
        if (parent == null) {
            structureRoot = new Component( node );
            currentParent = structureRoot;
            primaryStageLink.setTitle("CssMetaDataExtractor for [" + node.getClass().getName() + "]");
        }
        for (Node subNode : node.getChildrenUnmodifiable()) {
            Component child = new Component( subNode );
            currentParent.getChildren().add( child );
            if (subNode instanceof Parent) {                
                extractCssMetaData((Parent)subNode, child);
            }
        }
        structureRoot.setExpanded(true);
        structureTV.setRoot(structureRoot);
        if ( structureTV.getSelectionModel().getSelectedItems().size() == 0 ) {
            structureTV.getSelectionModel().selectFirst();
        }
    }
    private void showNodeProperties(Component component) {
        nodePropertiesRoot = new TreeItem( component.getNode().getClass().getName() );
        TreeItem<String> selector = new TreeItem("Selector");
        selector.setExpanded(true);
        selector.getChildren().add( new TreeItem( getSelectorHierarchy(component) ) );
        nodePropertiesRoot.getChildren().add( selector );
        if ( component.getNode().getPseudoClassStates() != null && component.getNode().getPseudoClassStates().size() > 0 ) {
            TreeItem<String> pseudoClasses = new TreeItem("PseudoClass States");
            pseudoClasses.setExpanded(true);
            for ( PseudoClass pc : component.getNode().getPseudoClassStates() ) {
                pseudoClasses.getChildren().add( new TreeItem( pc.getPseudoClassName() + " [" + pc.getClass().getName() + "]" ) );
            }
            nodePropertiesRoot.getChildren().add( pseudoClasses );
        }
        if ( component.getNode().getStyle() != null && component.getNode().getStyle().length() > 0 ) {
            TreeItem<String> style = new TreeItem("Style");
            style.setExpanded(true);
            style.getChildren().add( new TreeItem( component.getNode().getStyle() ) );
            nodePropertiesRoot.getChildren().add( style );
        }
        if ( component.getNode().getTypeSelector() != null & component.getNode().getTypeSelector().length() > 0 ) {
            TreeItem<String> typeSelector = new TreeItem("Type Selector");
            typeSelector.setExpanded(true);
            typeSelector.getChildren().add( new TreeItem( component.getNode().getTypeSelector() ) );
            nodePropertiesRoot.getChildren().add( typeSelector );
        }
        if ( component.getNode().getId() != null && component.getNode().getId().length() > 0 ) {
            TreeItem<String> id = new TreeItem("Id");
            id.setExpanded(true);
            id.getChildren().add( new TreeItem( component.getNode().getId() ) );
            nodePropertiesRoot.getChildren().add( id );
        }
        if ( component.getNode().getProperties() != null && component.getNode().getProperties().size() > 0 ) {
            TreeItem<String> properties = new TreeItem("Properties");
            properties.setExpanded(true);
            for ( Object key : component.getNode().getProperties().keySet() ) {
                properties.getChildren().add( new TreeItem( key + "=" + component.getNode().getProperties().get(key) ) );
            }
            nodePropertiesRoot.getChildren().add( properties );
        }
        if ( component.getNode().getAccessibleRole() != null ) {
            TreeItem<String> accessibleRole = new TreeItem("Accessible Role");
            accessibleRole.setExpanded(true);
            accessibleRole.getChildren().add( new TreeItem( component.getNode().getAccessibleRole() ) );
            nodePropertiesRoot.getChildren().add( accessibleRole );
            if ( component.getNode().getAccessibleRoleDescription() != null && component.getNode().getAccessibleRoleDescription().length() > 0 ) {
                accessibleRole.getChildren().add( new TreeItem( component.getNode().getAccessibleRoleDescription() ) );
            }
        }
        if ( component.getNode().getAccessibleText() != null && component.getNode().getAccessibleText().length() > 0 ) {
            TreeItem<String> accessibleText = new TreeItem("Accessible Text");
            accessibleText.setExpanded(true);
            accessibleText.getChildren().add( new TreeItem( component.getNode().getAccessibleText() ) );
            nodePropertiesRoot.getChildren().add( accessibleText );
        }
        nodePropertiesRoot.setExpanded(true);
        nodePropertiesTV.setRoot(nodePropertiesRoot);
        nodePropertiesTV.setShowRoot(false);
    }
    private String getSelectorHierarchy(Component component) {
        Component current = component;
        StringBuilder selectors = new StringBuilder();
        while (true) {
            StringBuilder sb = new StringBuilder();
            if ( current.getNode().getStyleClass().size() > 1 ) {
                sb.append("[ ");
                for ( String styleClass : current.getNode().getStyleClass() ) {
                    sb.append(".").append(styleClass).append(" | ");
                }
                sb.delete(sb.length()-3, sb.length());
                sb.append(" ]");
            } else if ( current.getNode().getStyleClass().size() == 1 ) {
                sb.append(".").append( current.getNode().getStyleClass() );
            } else {
                sb.append("NULL");
            }
            if ( current.getParent() != null ) {
                sb.insert(0, " > ");
                selectors.insert(0, sb);
                current = (Component)current.getParent();
            } else {
                selectors.insert(0, sb);
                break;
            }
        }
        return selectors.toString();
    }
    private void showCssProperties(Component component) {
        if ( component.getNode().getCssMetaData() != null && component.getNode().getCssMetaData().size() > 0 ) {
            cssPropertiesRoot = new TreeItem<CMDComponent>( new CMDComponent() );
            for ( CssMetaData cmd : component.getNode().getCssMetaData() ) {
                addProperty(cmd, component.getNode(), cssPropertiesRoot);
            }
            cssPropertiesRoot.setExpanded(true);
            cssPropertiesTV.setRoot(cssPropertiesRoot);
            cssPropertiesTV.setShowRoot(false);
        }
    }    
    private void addProperty(CssMetaData cmd, Node node, TreeItem<CMDComponent> parent) {
        TreeItem<CMDComponent> child = new TreeItem<CMDComponent>( new CMDComponent(cmd, node) );
        parent.getChildren().add( child );
        if ( cmd.getSubProperties() != null ) {
            for ( Object subcmd : cmd.getSubProperties() ) {
                if ( subcmd instanceof CssMetaData ) {
                    addProperty( (CssMetaData)subcmd, node, child );
                }
            }
        }
    }
    private class Component extends TreeItem<String> {
        private Node node;
        public Component(Node node) {
            super(node.getClass().getName());
            this.node = node;
        }
        public Node getNode() { return node; }
        public void setNode(Node node) { this.node = node; }
    }
    private class CMDComponent {
        private SimpleStringProperty name = new SimpleStringProperty();
        private SimpleStringProperty converterName = new SimpleStringProperty();
        private SimpleStringProperty initialValue = new SimpleStringProperty();
        private SimpleStringProperty styledValue = new SimpleStringProperty();
        private Node node;
        public CMDComponent() {
            this.name.set("none");
            this.converterName.set("none");
            this.initialValue.set("none");
            this.styledValue.set("none");
        }
        public CMDComponent(CssMetaData cssMetaData, Node node) {
            this.name.set(cssMetaData.getProperty());
            this.converterName.set(cssMetaData.getConverter().toString());
            if ( cssMetaData.getInitialValue(node) != null ) {
                this.initialValue.set(cssMetaData.getInitialValue(node).toString());
            } else {
                this.initialValue.set("null");
            }
            if ( cssMetaData.getStyleableProperty(node) != null ) {
                if ( cssMetaData.getStyleableProperty(node).getValue() != null ) {
                    this.styledValue.set( cssMetaData.getStyleableProperty(node).getValue().toString() );
                } else {
                    this.styledValue.set("null");
                }
            } else {
                this.styledValue.set("null");
            }
            this.node = node;
        }
        public String getName() { return name.get(); }
        public void setName(String name) { this.name.set(name); }
        public String getConverterName() { return converterName.get(); }
        public void setConverterName(String converterName) { this.converterName.set(converterName); }
        public String getInitialValue() { return initialValue.get(); }
        public void setInitialValue(String initialValue) { this.initialValue.set(initialValue); }
        public String getStyledValue() { return styledValue.get(); }
        public void setStyledValue(String styledValue) { this.styledValue.set(styledValue); }
    }
    private void createContent() {
        rootNode = new SplitPane();
        rootNode.setOrientation(Orientation.HORIZONTAL);
        rootNode.setDividerPosition(0, 0.25);
        primaryScene = new Scene(rootNode, 1300, 900);
        primaryStageLink.setScene(primaryScene);
        primaryStageLink.initStyle(StageStyle.DECORATED);
        SplitPane splitPane = new SplitPane();
        splitPane.setOrientation(Orientation.VERTICAL);
        splitPane.setDividerPosition(0, 0.15);
        splitPane.setDividerPosition(1, 0.6);
        rootNode.getItems().add(splitPane);
        ScrollPane scrollPane = new ScrollPane();
        group = new Group();
        scrollPane.setContent(group);
        splitPane.getItems().add(scrollPane);
        structureTV = new TreeView<>();
        structureTV.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
        structureTV.getSelectionModel().selectedItemProperty().addListener(
            (ObservableValue<? extends TreeItem<String>> observable, TreeItem<String> oldValue, TreeItem<String> newValue) -> {
                showCssProperties( (Component)newValue );
                showNodeProperties( (Component)newValue );
            }
        );
        splitPane.getItems().add(structureTV);
        nodePropertiesTV = new TreeView<>();
        splitPane.getItems().add(nodePropertiesTV);
        cssPropertiesTV = new TreeTableView();
        TreeTableColumn<CMDComponent, String> nameColumn = new TreeTableColumn<>("Name");
        nameColumn.setPrefWidth(250);
        nameColumn.setCellValueFactory(
            (TreeTableColumn.CellDataFeatures<CMDComponent, String> param) ->
                new ReadOnlyStringWrapper(param.getValue().getValue().getName())
        );
        TreeTableColumn<CMDComponent, String> initialColumn = new TreeTableColumn<>("Initial Value");
        initialColumn.setPrefWidth(275);
        initialColumn.setCellValueFactory(
            (TreeTableColumn.CellDataFeatures<CMDComponent, String> param) ->
                new ReadOnlyStringWrapper(param.getValue().getValue().getInitialValue() )
        );
        TreeTableColumn<CMDComponent, String> styledColumn = new TreeTableColumn<>("Styled Value");
        styledColumn.setPrefWidth(275);
        styledColumn.setCellValueFactory(
            (TreeTableColumn.CellDataFeatures<CMDComponent, String> param) ->
                new ReadOnlyStringWrapper(param.getValue().getValue().getStyledValue() )
        );
        TreeTableColumn<CMDComponent, String> converterColumn = new TreeTableColumn<>("Default Converter");
        converterColumn.setPrefWidth(170);
        converterColumn.setCellValueFactory(
            (TreeTableColumn.CellDataFeatures<CMDComponent, String> param) ->
                new ReadOnlyStringWrapper(param.getValue().getValue().getConverterName() )
        );
        cssPropertiesTV.getColumns().setAll(nameColumn, initialColumn, styledColumn, converterColumn);
        rootNode.getItems().add(cssPropertiesTV);
    }}
    

    【讨论】:

    • 非常好的实用程序!
    【解决方案2】:

    您尝试风格化的子元素实际上是一个扩展javafx.scene.text.TextLabeledText 对象。从JavaFX CSS Reference Guide : Text 可以看出,它有自己的属性以及字体和形状。这些属性都不能让您自定义 *Label" 区域,只能自定义文本。

    我的建议是使用不带文本的单选按钮,并使用其他可自定义的组件在其旁边放置一个“标签”。

    【讨论】:

    • 如果这个子元素是LabeledText,那么这就解释了风格化的问题,但是你在哪里找到的呢?在 CSS 参考指南中,它被指定为 javafx.scene.control.Label,而不是 LabeledText...
    • RadioButton 的默认外观是 RadioButtonSkin。该皮肤类扩展了包含 LabeledText 作为字段的抽象类 LabeledSkinBase。 .
    【解决方案3】:

    您不需要明确地设置标签的样式。

    如果你想改变标签的颜色,你可以很容易地做到这一点:

    .radio-button {
        -fx-text-fill: yourColor;
    }
    

    【讨论】:

    • 没有。我需要在标签 sub 周围做一个虚线边框,就像对应的 Win8 元素一样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-27
    • 2011-05-15
    • 2017-06-21
    • 2021-09-25
    • 2012-11-27
    • 1970-01-01
    相关资源
    最近更新 更多