Make JEditorPane use the system font

October 28, 2008

JEditorPane is a powerful component. One of it’s main strengths is the ability to render auto-wrapping text. But JEditorPane doesn’t come free of imperfections. My biggest gripe is that as soon as you install an HTMLEditorKit (say to render some hyperlinks or custom colored text) the default font changes to Times New Roman [insert finger in throat].

Here’s what a JEditorPane setup for HTML rendering gives you by default:

        // create a JEditorPane that renders HTML.
        JEditorPane editorPane = 
                new JEditorPane(new HTMLEditorKit().getContentType(),text);
        editorPane.setOpaque(false);
        editorPane.setBorder(null);
        editorPane.setEditable(false);

Not ideal if your trying to blend in with other components like labels and buttons.

Unfortunately, simply calling set font on JEditorPane will have no effect, as the default font is pulled from a style sheet rather than the JComponent. There is, however, a clever way around the errant font default. The best way to change the default font in an HTML rendering JEditorPane, is to alter the style sheet like this:

        // create a JEditorPane that renders HTML and defaults to the system font.
        JEditorPane editorPane = 
                new JEditorPane(new HTMLEditorKit().getContentType(),text);
        // set the text of the JEditorPane to the given text.
        editorPane.setText(text);
        
        // add a CSS rule to force body tags to use the default label font
        // instead of the value in javax.swing.text.html.default.csss
        Font font = UIManager.getFont("Label.font");
        String bodyRule = "body { font-family: " + font.getFamily() + "; " +
                "font-size: " + font.getSize() + "pt; }";
        ((HTMLDocument)editorPane.getDocument()).getStyleSheet().addRule(bodyRule);
        
        editorPane.setOpaque(false);
        editorPane.setBorder(null);
        editorPane.setEditable(false);

and you end up with this:

The real beauty of this, is that it works across platforms, always giving you the system default font.

About these ads

14 Responses to “Make JEditorPane use the system font”

  1. Steve McLeod Says:

    Nice. Trying to customise JEditorPane has given me severe headaches. For example, making unordered lists use nice bullets instead of horrible non-anti-aliased blobs was nigh on impossible.

  2. Ken Says:

    I agree; I’ve not used JEditorPane before *just* because of the poor rendering of bullets on Windows!


  3. Dude, that’s so cool! I had no idea HTMLDocument was sophisticated enough to respect style sheet modifications.

  4. Ken Says:

    Sure is…now if only JEditorPane could render *all* of the CSS standard!


  5. [...] Orr has a tip to use look-and-feel consistent fonts onthe JEditorPane component. A fortunate coincidence had Ken [...]


  6. Excellent tip. Thanks for that. Be aware however, that you’re second code example is slightly incorrect. You reference fEditorPane when you created editorPane.

    FYI, You can replace the list bullets with images of your choice using the CSS directive: list-style-image

    Assuming a URL pointing to an image, you can add this to your code example to get nicer bullet points

    ((HTMLDocument)editorPane.getDocument()).getStyleSheet().addRule(“ul {list-style-image: “+url.toString()+”; }”);

    Regardless of this, in my experience, JEditorPane is really the worst kind of code – tt promises much and delivers very litte. Avoid it if you can.

  7. Ken Says:

    Good catch Joel…I’ve updated the code.

    Your tip on supplying bullet images via the CSS list-style-image directive is a nice way work-around the lumpy bullets on Windows.

  8. hmd Says:

    Just found this, and it looks nice. But does it play well?

    My main interest here would be in changing the default text color to match the component foreground, so the default blends better with look and feel. But if you just add a rule, won’t that clobber any explicit styles in the document?

    And will this work if you reload the document from a different source? Or will it discard this rule?

    A slightly better approach might be to modify the style sheet at the editor kit:
    ((HTMLEditorKit)getEditorKit()).getStyleSheet().addRule(…).
    I think that by default HTMLEditorKit uses a static style sheet instance, so if you don’t want this to apply to all JEditorPane instance, you’d have to subclass.

  9. Ken Says:

    Hi hmd,

    All great questions. Adding a color style would be easy – the color property would probably do the trick. Tracking the JEditorPane’s foreground color would be slightly more work, but easy enough with a PropertyChangeListener.

    I’m not sure what will happen if you reload the document from a different source, but presumably, if your using this technique, your text source is local and relatively static (at least that’s what I was presuming!).

    As far as adding a rule to the style sheet…I’m pretty sure that myHtmlDocument.getStyleSheet() returns an instance variable rather than a static variable.

    -Ken

  10. hmd Says:

    Yes, the document has its own, but the editor kit documentation says it has a static implementation. Using the editor kit to do this is a little more generalizable.

    I tried this out a bit, and ended up subclassing the HTMLEditorKit, modifying the L&F code so the EditorPaneUI installs the subclass editor kit as the default for text/html, and overriding getStyleSheet() in the subclass. There I can create a new style sheet, add the HTMLEditorKit.getStyleSheet() to it, and add rules to the new one – for colors, fonts, bullet icons, whatever.

    This way the process is fairly automatic – the new style rules are inherited by any HTMLDocument so long as the subclassed editor kit is used to create the document. Anything in the document that provides styles will override the inherited rules properly.

    Dealing with a change in the background property is harder than it might look, because you need to find the style sheet(s) where the rules where added, replace the old rules, and re-render the associated documents.

  11. Riquochet Says:

    Beautiful! I looked everywhere for this type of thing. Nice job.

    I actually needed it for laying out a multiline tree node and your code was the linchpin that brought it all together.

    Thanks.

  12. freelancer Says:

    that was excellent tip! Fixed several issues for me!

  13. Zing Says:

    Well, this works. But bullets still look like crap (I found this post while searching around for solutions to this.)

  14. Justin Says:

    Thank you, this is a great workaround!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 27 other followers

%d bloggers like this: