Important (2015-06-30): Starting with Java 8u60, JavaFX provides by implicitly scaling all coordinates and image sizes to the current system DPI setting. So the manual scaling workaround described below is now only required for previous versions. The original post follows but now applies only to Java 8u45 and older. End of addendum
JavaFX is one of the GUI frameworks covered in my overview, . As noted there, JavaFX 2.2 is partly but not fully suited for high DPI scaling on Windows. The default font and all standard controls are automatically scaled whereas explicitly specified sizes are not, with the exception of (some?) CSS em sizes. This post shows how Oracle’s own Windows samples break in high DPI mode, and how to work around this defect until perhaps one day JavaFX scales its coordinate system.
Oracle’s official JavaFX documentation includes Joni Gordon’s three-part tutorial, . The code showcased there is typical for JavaFX sample code you can find on the web: explicit sizes in Java or CSS are mixed freely (and thoughtlessly) with default-sized fonts and self-sized controls. We’ll pick the second and third tutorial to demonstrate why this is a bad idea.
Procedure. The following is based on the June 2013 revision of Oracle’s tutorials. I downloaded the ZIP archives for each tutorial and recompiled the source code in JavaFX 2.2 without changes, except to complete various tutorial steps. Then I ran each program at four different DPI settings on my Windows 8 system and took the screenshots you see below. The DPI settings are all standard ones:
All JavaFX applications register themselves as DPI-aware on Windows, so they always run with XP style scaling and never use Vista DPI virtualization, regardless of whether XP style scaling is forced or not. Please read if you don’t understand the last sentence. The bottom line is that there are no Windows settings to work around JavaFX layout failures at high DPI settings. The developers must fix their programs.
First Sample. The first sample is taken from the second tutorial, . Here all controls are sized in Java code, with some inline CSS for button fonts. The unchanged sample code produces “Figure 2-2 Desired Sizes” on the tutorial page. Observe how the 96 DPI version looks great, the 120 DPI version starts misarranging buttons, the 144 DPI version has ugly overlaps, and the 192 DPI version is entirely unusable.
What happened? The Scene size was explicitly set to 300×400 pixels. While the buttons scaled with the Windows default font, the Scene and its nested containers could not grow to accommodate the growing buttons. Also note that the “Exit” label was explicitly set to 15pt – intended as 25% bigger than the default font, but actually much smaller at high DPI.
Second Sample. The second sample is taken from the third tutorial, . I completed all suggested changes to the CSS stylesheet to produce “Figure 3-3 Styled with Images,” the last picture on the tutorial page. Once again, the 96 DPI version looks great and then everything falls apart.
To reiterate, all of the above layout failures are the result of mixing explicit sizes with default sizes. JavaFX automatically scales its default font and standard controls, but not explicitly specified positions and sizes. That means you must scale them manually, based on the JavaFX default font size. The idea is similar to the concept of in HTML/CSS. To obtain a scalable page layout, you define all positions and sizes in terms of “root em” (rem), the em size of the default font. Obtaining a JavaFX application’s root em is easy:
final double rem = javafx.scene.text.Font.getDefault().getSize();
That’s the default font size in typographical points (1/72″, CSS pt). You can obtain this value whenever you need it, or cache it since it won’t change while the application is running. (That is, until JavaFX supports the new dynamic in Windows 8.1.) Now, instead of supplying explicit pixel measures to positioning and sizing methods, you specify fractions or multiples of rem, like so:
// scalable version of 300x400 scene, assuming rem=12 at 100%
Previous Next
.