Google has been kind enough to pull together a collection of great free fonts at http://www.google.com/webfonts. For ages I have wanted a easy way to use these in my JavaFX applications. This week I added basic support to JavaFX for CSS @font-face support (see RT-10343). It should be going into JDK 8-b69 which will be available later this week.
So all you need to now is go to Google Web Fonts site, find the font you want:
Then click the “Quick-use” button
That will take you to a page telling you steps to use that font in a web application. For JavaFX we need the address for the CSS file which is shown in the box in Step (3):
So once you have the address like “http://fonts.googleapis.com/css?family=Gafata” you can use it in your JavaFX application. Here is a simple application:
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.stage.Stage; public class HelloFontFace extends Application { @Override public void start(Stage primaryStage) { Label label = new Label("Hello @FontFace\n-- Gafata --"); label.setStyle("-fx-font-family: Gafata; -fx-font-size: 80;"); Scene scene = new Scene(label); scene.getStylesheets().add("http://fonts.googleapis.com/css?family=Gafata"); primaryStage.setTitle("Hello @FontFace"); primaryStage.setScene(scene); primaryStage.show(); } public static void main(String[] args) { launch(args); } }
The key lines here are:
scene.getStylesheets().add("http://fonts.googleapis.com/css?family=Gafata");
Which tells JavaFX to load the stylesheet from Google and add it to the scene’s available styles. The second line is:
label.setStyle("-fx-font-family: Gafata; -fx-font-size: 80;");
This sets the style of the label to use the loaded font by name and make the font size 80px. The result when you run it is:
That is it, you are now using web fonts in JavaFX 🙂 You can also use them in cool ways along with the new rich text features of JavaFX 8 to create multi-line multi-style wrapping text like in the picture at the top of this post. The code for that is:
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.text.Text; import javafx.scene.text.TextFlow; import javafx.stage.Stage; public class CssFontFaceTest extends Application { @Override public void start(Stage primaryStage) { TextFlow flow = new TextFlow(); flow.setPrefWidth(750); final Text t1 = new Text("Hello @FontFace - Grand Hotel."); t1.setStyle("-fx-font-family: 'Grand Hotel'; -fx-font-size: 80;"); flow.getChildren().add(t1); final Text t2 = new Text("Hello @FontFace - New Rocker"); t2.setStyle("-fx-font-family: 'New Rocker'; -fx-font-size: 80; -fx-fill: orange;"); flow.getChildren().add(t2); Scene scene = new Scene(flow); scene.getStylesheets().add("http://fonts.googleapis.com/css?family=New+Rocker"); scene.getStylesheets().add("http://fonts.googleapis.com/css?family=Grand+Hotel"); primaryStage.setTitle("Hello @FontFace"); primaryStage.setScene(scene); primaryStage.show(); } public static void main(String[] args) { launch(args); } }
You can see here we are loading two fonts, you can load as many as you like. So go have fun and enjoy creating great typography in your JavaFX apps.
My ignorance of how CSS + JavaFX works may bleed through here, but there’s something about this that doesn’t sit right with me.
Doesn’t this make it a little too easy for people to accidentally create dependencies on external resources they don’t control? I can see myself using the above setup for prototyping since it’s convenient, but I can also see myself forgetting to change a reference to an external stylesheet at some point (after I download / bundle the font locally).
Now here’s the part where I don’t know how things work. Is there a way I can check everything at compile time to make sure there aren’t any references to resources that aren’t available on the classpath?
Furthermore, it is unclear whether those fonts are cached locally (where?), or need to be downloaded each time the stylesheet is applied (or the application runs).
Is this supposed to work with Java 7 also or only with Java 8 ? When I tried it with Java 7, I get this:
java.io.IOException: Server returned HTTP response code: 400 for URL: http://fonts.googleapis.com/css?family=Gafata.bss
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1625)
at java.net.URL.openStream(URL.java:1037)
at com.sun.javafx.css.Stylesheet.loadBinary(Stylesheet.java:201)
at com.sun.javafx.css.StyleManager.loadStylesheetUnPrivileged(StyleManager.java:572)
at com.sun.javafx.css.StyleManager.loadStylesheet(StyleManager.java:411)
at com.sun.javafx.css.StyleManager.updateStylesheets(StyleManager.java:858)
regards,
Wim
Is there a way to add these exclusively through CSS?
@John, I know it’s 5 years later, but in case anyone wanted to add fonts just through CSS, you can use `@import`.
It’s gotta be the first thing in your stylesheet.
`@import url(“http://fonts.googleapis.com/css?family=Gafata”);`
See https://www.w3.org/TR/CSS21/cascade.html#at-import
and https://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html#introatrules
The website has since had a redesign.
Instead of “Quick Use”, look for a red plus (+) button, and then click the black toast message.