13

Does anybody know how to get JTextArea to display a fixed size font on all platforms?

I want to make a simple code editor with save/open functionality, which is simple enough, but I would like to get font to be fixed-size, preferably courier new.

The problem is that courier new is proprietary apparently, and not only is it not installed by default on many systems, but on most modern systems, it is set to cleartype be default, which makes it look like garbage.

I am tempted to make my own JPanel with update-render-paint and reinvent the JTextArea, and save fonts as fixed-size bitmaps, but this approach appears silly, and very time consuming.

I would like to include a free fixed-size font to the project and use that font on all platforms, which appears possible. However, modern systems appear to force-smooth all fonts, which I would like to prevent it from doing.

Sadly, it appears that Swing automatically abides by system preferences so without destroying user's settings, it appears to be a no go.

So in short, is there a way to get JTextArea to display a fixed-width font and disable font smoothing/antialiasing (or at least toggle), or is this task impossible using swing?

Thanks ahead of time!

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Dmytro
  • 5,068
  • 4
  • 39
  • 50

2 Answers2

33

You can use the logical font "monospaced". While it guarantees to have a font that has the same size for all characters, it won't be the same on all platform.

import java.awt.Font;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

public class TestTextArea {

    private void initUI() {
        JFrame frame = new JFrame("test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JTextArea textArea = new JTextArea(24, 80);
        textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
        frame.add(new JScrollPane(textArea));
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestTextArea().initUI();
            }
        });

    }

}

Alternatively, you could look up a "free" font which meets your need, embed that font in with code and load it with java.awt.Font.createFont(int, InputStream).

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117
  • Thanks, that answers the question, but I am still curious if I can make the monospaced font guarantee that it will not be antialiased. Is this possible? – Dmytro Apr 29 '13 at 13:37
  • 2
    @Dmitry There are several ways to disable anti-aliasing: 1) [`System.setProperty("awt.useSystemAAFontSettings","false");`](http://docs.oracle.com/javase/6/docs/technotes/guides/2d/flags.html#aaFonts) `System.property("swing.aatext", "false"); 2) You can set the RenderingHints on the `Graphics` object of the `paintComponent` method to disable TEXT_ANTI_ALIASING (`((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, Boolean.FALSE);` but you won't have an absolute guarantee that someone is not going to change that afterwards. – Guillaume Polet Apr 29 '13 at 13:49
  • I'm not worried about change afterwords, I'm worried about default settings :). Thanks a lot! – Dmytro Apr 29 '13 at 13:52
  • 1
    @Dmitry Small correction, you can't use `Boolean.FALSE` for the hint value. Use `RenderingHints.VALUE_TEXT_ANTIALIAS_OFF` instead. Sorry about that. – Guillaume Polet Apr 29 '13 at 13:56
  • Thanks :), I got it working. Although now I am having a battle with finding a font chooser, as it's not included in java by default. – Dmytro Apr 29 '13 at 14:38
  • 3
    @Dmitry `JComboBox cb = new JComboBox(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()); JSpinner spinner = new JSpinner(new SpinnerNumberModel(12, 4, 240, 1)); JCheckBox italic = new JCheckBox("Italic"); JCheckBox bold = new JCheckBox("Bold");` Add all of those in a JPanel, add the wraping code and you are done. – Guillaume Polet Apr 29 '13 at 16:31
2

I came close to a solution by using JTextPane instead of JTextArea by setting the content type of the JTextPane to text/html and setting the text as a html content.

JtextPane textPane;
String text;

// initialization

textPane.setContentType("text/html");
textPane.setText(""
        + "<html>"
        + "<body>"
        + "<p>"
        + "<tt>"+text.replaceAll(" ", "&nbsp;").replaceAll("\n", "<br>")+"</tt>"
        + "</p>"
        + "</body>"
        + "</html>"                
        + "");

<tt> tag is making the text monospaced and all white spaces and new line characters of the text have replaced with html space entity and <br> tag, respectively. I tested the output in both Windows and Ubuntu OSes and they were same.

CLOUGH
  • 691
  • 11
  • 16