Setting stylesheets declaratively in FXML

后端 未结 3 727
余生分开走
余生分开走 2021-02-18 20:37

In HTML we are used to niceties of being able to set stylesheets programmatically like


But the examples of

相关标签:
3条回答
  • 2021-02-18 21:03

    You can set stylesheets on Parent nodes using:

    parent.getStylesheets().add("/resources/shell.css");
    

    Because the elements and attributes usable in FXML are derived from the public JavaFX Java API, then you can also assign stylesheets to a Parent node using an FXML stylesheets element (or interchangeably an attribute). As all containers extend Parent, you can set one or more custom stylesheets on any container you reference in FXML:

    <?xml version="1.0" encoding="UTF-8"?>
    <?import javafx.scene.layout.*?>
    <?import java.net.URL?>
       ....
    <?scenebuilder-stylesheet fruitcombo.css?>
    
    <AnchorPane prefHeight="205.0" prefWidth="168.0"
       styleClass="layout"
       fx:controller="fruit.FruitComboController"
       xmlns:fx="http://javafx.com/fxml">
       <children>
          ....
       </children>
       <stylesheets>
          <URL value="@fruitcombo.css" />
       </stylesheets>
    </AnchorPane>
    

    See the fxml file in this sample for a complete executable sample of referencing a css file from an fxml file.

    There are a couple of nice to have features in the above code:

    The strange @ prefix in the stylesheets URL isn't strictly needed, but can be used to take advantage of JavaFX's location resolution. "The location resolution operator (represented by an "@" prefix to the attribute value) is used to specify that an attribute value should be treated as a location relative to the current file rather than a simple string."

    The following line isn't required at runtime, but is used by the SceneBuilder tool to locate the required css stylesheet at design time if you are using that tool:

    <?scenebuilder-stylesheet fruitcombo.css?>
    

    Update regarding the comment

    Warning: It's FXML 1.0, it's not working in 2.0, javafx.fxml.LoadException: URL is not a valid type.

    This comment is a bit incorrect I think. As far as I am aware, there is no such thing currently as FXML 2.0.

    The reason the commenter received a LoadException was because the indicative snippet in this post was not importing the the java.net.URL class into the FXML document. I updated the snippet to include the java.net.URL import and add some more ellipsis .... to clarify the intent of the snippet. An ellipsis means "a series of dots that usually indicates an intentional omission of a word, sentence, or whole section from a text without altering its original meaning".

    To best understand this answer it is suggested to compile and run the linked sample code.

    Warning against using InputStream load functions in FXMLLoader

    I strongly advise constructing an new FXMLLoader with a location, rather than using the FXMLLoader.load(InputStream) function. When the static load() function is used, then relative location references cannot be resolved as there is no base location for the FXML file.

    I.e., don't do:

     InputStream input = this.getClass().getResourceAsStream("layout.fxml");
     FXMLLoader loader = new FXMLLoader.load(input);
     Parent content = loader.load();
    

    Instead do:

     String url = this.getClass().getResource("layout.fxml").toExternalForm();
     FXMLLoader loader = new FXMLLoader(url);
     Parent content = loader.load();  
    
    0 讨论(0)
  • 2021-02-18 21:05

    Yes, see for instance example 4-8 of this tutorial, by applying the following attribute to a node:

    stylesheets="fxmlexample/Login.css"
    

    e.g.

    <GridPane stylesheets="fxmlexample/Login.css">
    
    0 讨论(0)
  • 2021-02-18 21:06

    If you are going to use fxml with JavaFX you should take some time to download and use SceneBuilder. Once you do that use of css style sheets becomes simple. Of course, use NetBeans since with SceneBuilder running, opening the prebuilt dxml file in the NetBeans dxml boilerplate application causes it to be automatically open for editing in SceneBuilder. Once you have ripped out all the StackPlane, button and label and put in the controls and containers you really want, just add the style sheet directly to SceneBuilder. In the main menu, under Preview, there is a menu selection for CSS style sheets. Selecting it brings up a submenu which will let you load a style sheet file.

    Once the file is loaded, the controls will show to be skinned according to the rules in the style sheet they won't show that skin until you select each one in the properties section of SceneBuilder and declare that style sheet as applied to that control. Then the style will show when the application runs.

    0 讨论(0)
提交回复
热议问题