Skip to main content

Font Hints for Custom Components

Posted by chet on January 10, 2007 at 2:40 PM PST

I just got finished writing a small section on text-anti-aliasing for Romain's
and my Filthy Rich Clients book (did you notice how smoothly I slid that
teaser into the discussion?). It seemed like such a bite-sized and useful bit
of info that I thought it would go well here, so here it is:


Setting text anti-aliasing hints can be confusing, especially with new
RenderingHints added in Java SE 6 for LCD text. What text quality do you want?
What is appropriate for the application? What is appropriate for the platform?
What does your user prefer?


A better solution than setting hints directly in most situations is for your
application to figure out what the user’s native desktop settings are for fonts
and to do something similar for their Java application. This, in fact, is what
Swing does in some of its look and feels (Metal, Windows, and GTK in
particular); it queries desktop properties for how text is rendered by native
applications and sets RenderingHints appropriately.


Custom components which perform their own text operations do not get this Swing
behavior; the Graphics object you get in paintComponent is set up with
defaults that do not know anything about the desktop properties. So if you want
your strings to look like Swing’s strings, or to look like native applications'
text for that matter, you’ll need to mimic Swing.


I wrote a simple app that shows how to do this, by rendering one string with the
default Graphics object in paintComponent (for comparison), setting
RenderingHints appropriately to match desktop settings, and then rendering
another string with this modified Graphics object. Here is the result on my
test system (Windows Vista, with ClearType enabled):




fontscreenshot.png

First, note that the image may look a lot better on my display than it does here
for you; LCD text rendering is optimized to look good on the runtime display,
not whatever display you may be using to view this screenshot. But the
important thing to note here is not how good it looks here, but that the two
strings are different because the second string was drawn after setting the
appropriate desktop property hints on the Graphics object.


Here is the simple code that produced this output:


g2d.drawString("Unhinted string", 10, 20); 
if (desktopHints == null) {
    Toolkit tk = Toolkit.getDefaultToolkit();
    desktopHints = (Map) (tk.getDesktopProperty("awt.font.desktophints"));
}
if (desktopHints != null) {
    g2d.addRenderingHints(desktopHints);
}
g2d.drawString("Desktop-hinted string", 10, 40);
       

Here, we first check to see whether desktopHints is null; this keeps us from
re-creating it every time through paintComponent. Desktop properties will probably
not change during the lifetime of your Java application, but to be
completely correct, we should establish a listener on the desktop properties to
get notified if they do change, and to recreate desktopHints at that time; the JavaDocs on this subject tell you how you
can do this. To get the desktop properties we do a query on
awt.font.desktophints, which returns a Map of all of the properties. Then we
simply add all of those hints through a call to Graphics2D.addRenderingHints().
Now our Graphics object is set up to render text just like native applications.


For more information on desktop properties, check out the article “AWT Desktop
Properties” in the JavaDocs (the document name is DesktopProperties.html, but
it might be easier to find it by clicking on the link in the JavaDoc for
Toolkit.getDesktopProperty).



Thanks to Phil Race for helpful pointers on this one

Related Topics >>