使用CSS在JavaFX中设置RadioButton子元素的样式

时间:2016-02-08 20:28:37

标签: java css javafx javafx-8

我试图通过使用CSS改变JavaFX中RadioButton的外观,但面临问题。 根据JavaFX CSS参考指南,元素结构由子元素组成:

   radio — Region
      dot — Region
   label — Label

在modena.css中风格化的Subelement无线电:

.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参考指南除外)?

3 个答案:

答案 0 :(得分: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);
}}

答案 1 :(得分:0)

您无需明确设置标签样式。

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

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

答案 2 :(得分:0)

您尝试样式化的子元素实际上是一个 LabeledText 对象,它扩展了 javafx.scene.text.Text 。从JavaFX CSS Reference Guide : Text可以看出它有自己的属性加上字体和形状。这些属性都不允许您自定义* Label“区域,仅自定义文本。

我的兴趣是使用没有文字的单选按钮,并使用可自定义的其他组件在其旁边放置“标签”。