When you are a UI developer coming from Swing like me then there is a good chance that you are still setting images / icons directly in your code. Most likely something like this:
import javafx.scene.control.Label; import javafx.scene.image.ImageView; public class MyLabel extends Label { public MyLabel() { setGraphic(new ImageView(MyLabel.class. getResource("image.gif").toExternalForm())); } }
In this example the image file is looked up via Class.getResource(), the URL is passed to the constructor of the ImageView node and this node is set as the “graphic” property on the label.
This approach works perfectly well but with JavaFX there is a more elegant way. You can put the image definition into a CSS file, making it easy for your and / or others to replace it (once the marketing department has decided to change the corporate identity once again).
The same result as above can be achieved this way:
import javafx.scene.control.Label; public class CSSLabel extends Label { public CSSLabel() { getStyleClass().add("folder-icon"); } }
Now you obviously need a CSS file as well:
.folder-icon { -fx-graphic: url("image.gif"); }
And in your application you need to add the stylesheet to your scene graph. Here we are adding it to the scene.
import javafx.application.Application; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.stage.Stage; public class MyApplication extends Application { public void start(Stage primaryStage) throws Exception { CSSLabel label = new CSSLabel(); label.setText("Folder"); label.setAlignment(Pos.CENTER); Scene scene = new Scene(label); scene.getStylesheets().add(MyApplication.class. getResource("test.css").toExternalForm()); primaryStage.setScene(scene); primaryStage.setTitle("Image Example"); primaryStage.setWidth(250); primaryStage.setHeight(100); primaryStage.show(); } public static void main(String[] args) { launch(args); } }
With this approach you have a clean separation of your controls and their apperance and you allow for easy customization as well.
Very much like web developers have done it with HTML + CSS. I like it 😉
But there is another approach: Using Icon Fonts. Yes, you have to do it in the code again, but you get scalable vector images as a result. Or do you know a way to put icon fonts in CSS?
FYI: in this example the image file needs to placed in the same location as the css file. However, you can define relative paths if you want to have separate folders for css and png/gif files.
I love to use css… however there is a big disadvantage when working with several jar files in your app. Locating a url() in javafx css does not seem to follow the same rules as normal resource location.
Our app has one base jars, containing base classes & resources like images, and it is referenced by more detailed classes in a second jar.
If we want to define a css (inside the second jar) pointing a resource of the first jar, sadly this does not work. Then we need to use the resource approach or duplicate resources which is not good 🙁
[…] Dirk Lemmermann has another JavaFX tip: Define Icons in CSS. […]
[…] Dirk Lemmermann has another JavaFX tip: Define Icons in CSS. […]
This doesn’t seem very modular to me. Unless the css goes inside the Jar. In that case, what’s the point? You just end up with an extra file floating around and you still need to rebuild the Jar when you make a change to the css file.