Skip to main content

Font Hints for Custom Components

Posted by chet on January 10, 2007 at 5:40 PM EST

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 >>