The upcoming Java release 8u60 is set to finally fix the JavaFX DPI scaling issues on Windows that I described back in August 2013. To recap, JavaFX would scale the default application font to the current Windows DPI setting and the built-in controls would generally scale themselves around that font size. However, explicitly specified pixel coordinates and sizes, whether in code or CSS, remained unscaled, and so did any images loaded by the application. You had to scale all those manually, by multiplying with a scaling factor based on the (scaled) default font size. Obviously this made writing DPI-aware applications rather cumbersome and encouraged developers to simply not bother at all.
Java 8u60 removes this annoyance by implicitly scaling all pixel coordinates, as well as loaded images, to the current Windows DPI setting relative to the 100% baseline. This is exactly what Windows Presentation Foundation (WPF) and modern browser layout engines are doing, and it’s really a necessity for painless user interface development. Even better, if you were using manual coordinate scaling based on the default font size your application will continue to work because font size queries now simply return the 100% sizes (12 points or 16 pixels for one line of text), turning your manual scaling into a harmless no-op when running on 8u60 or later.
Oracle’s Layout Samples Revisited
I have run some tests on the current preview release, JDK 8u60 build 21, which is theoretically available here. Unfortunately Oracle’s servers are rather broken and I was unable to get a working download for the past couple of days. With the 64-bit JDK I did manage to get before the servers broke down, I checked that my JavaFX applications that employ manual DPI scaling still work fine at 200% (192 DPI) and also re-ran Oracle’s layout tutorials that I used as demonstrations in my original post. Please see there for screenshots of how high DPI settings scrambled the GUI layout in JavaFX 2.2.
There were some changes to the JavaFX layout mechanisms unrelated to DPI scaling, so I’ll first show how the current release Java 8u45 renders the first sample application. The left screenshot shows how the application starts up: the explicitly sized
Scene is still clearly too small for its contents, but at least the hosted
BorderPane now automatically extends to the required size. Enlarging the window shows an already semi-decent layout in the right screenshot. Two errors remain: the
ListView has an explicit width that’s too narrow at 200%, and the explicitly sized “Exit” font is smaller than the 200% default font but was intended to be larger.
The next screenshot shows the same application running on Java 8u60 build 21. Everything looks as intended now, virtually identical to Oracle’s sample screenshot at 100%. The start-up window size is correct, the
ListView is wide enough, and the “Exit” label is bigger rather than smaller than the other labels.
The last screenshot shows the second application I used in my original post. This sample features CSS layout with explicit pixel sizes and PNG images as part of the user interface, all of which remained unscaled in JavaFX 2.2. Java 8u45 still produced the same result (so no separate screenshot) but Java 8u60 build 21 once again fixes everything and produces a layout at 200% that looks identical to the 100% version.
Well, except for one small thing – did you notice? The
HBox behind the “Save/Cancel” buttons is not high enough for the rotated buttons. That, however, is a layout change that must have happened at some point between JavaFX 2.2 and Java 8u60: the
HBox apparently no longer takes the button rotation into account when sizing itself to its contents. I’m not sure if this is intentional or a bug, but I did verify that it looks just the same at 100% as at 200% DPI scaling.
Jim Graham has documented the current state of Windows DPI scaling and planned updates on the OpenJFX mailing list – make sure to read the entire thread, there are lots of interesting comments. Here’s a summary of the most important points:
- Java applications still advertise themselves as “system DPI aware,” i.e. they don’t opt into the new per-monitor DPI scaling of Windows 8.1. Support for this feature is planned for Java 9.
- Three new
java.exeflags allow you to explicitly specify a DPI scaling factor and manipulate scaling strategies. Please see Jim Graham’s post above for a detailed description.
- JavaFX supports an Apple convention on Windows: a pair of image files named
firstname.lastname@example.org the same image, one twice the resolution of the other. The appropriate version is loaded depending on current DPI settings.
- It’s not yet possible to programmatically circumvent implicit coordinate scaling in order to access physical monitor pixels. Such a feature is probably coming in a future release.
Java 8u60 was a very pleasant surprise for me, as I had not expected fully automatic DPI scaling before Java 9 (if ever). This should make JavaFX a great deal more attractive as a WPF alternative. Speaking of which, once Java 8u60 has been officially released I’ll update my article on DPI Scaling in Windows GUIs accordingly, so we’ll have a side-by-side comparison of JavaFX and WPF at 120–144 DPI. Finally, one thing Java 8u60 won’t fix is DPI scaling in AWT/Swing… so NetBeans will unfortunately continue to feature increasingly minuscule button labels.
2015-08-24: While updating my comparison of Windows GUIs at 96–144 DPI, I discovered that JavaFX 8u60 (release version) actually special-cases 120 DPI and does not scale coordinates at that resolution. See this post for more information.