RSyntaxTextArea icon indicating copy to clipboard operation
RSyntaxTextArea copied to clipboard

Using custom registered font, `setFont()` is not working, but `getFont*()` overridden makes it work

Open ron190 opened this issue 1 year ago • 4 comments

Hello, thank you for your work on this great library!

Description Using setFont() on RSyntaxTextArea is not working for registered font (or for any unclear root cause), the custom font is ignored and the default font is used instead.

Issue is fixed when we override the methods getFont*() (see below).

Steps to Reproduce

  • First load a font :
var graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
InputStream fontStream = new BufferedInputStream(
    UiUtil.class.getClassLoader().getResourceAsStream("swing/font/UbuntuMono-R-ctrlchar.ttf")
);
var ubuntuFont = Font.createFont(Font.TRUETYPE_FONT, fontStream);
graphicsEnvironment.registerFont(ubuntuFont);
  • The next code displays the default font instead of the custom font (see Actual behavior):
RSyntaxTextArea textArea = new RSyntaxTextArea("text");
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL);
textArea.setFont(new Font("Ubuntu Mono", Font.PLAIN, 12));
  • The next code overrides the methods getFont*() and displays the custom font properly (see Expected behavior):
RSyntaxTextArea textArea = new RSyntaxTextArea("text") {
        @Override
        public Font getFont() {
            return new Font("Ubuntu Mono", Font.PLAIN, 12);
        }
        @Override
        public Font getFontForToken(Token token) {
            return new Font("Ubuntu Mono", Font.PLAIN, 12);
        }
        @Override
        public Font getFontForTokenType(int type) {
            return new Font("Ubuntu Mono", Font.PLAIN, 12);
        }
    };
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL);

Expected behavior Correct custom font is displayed when overridden :

Image

Actual behavior Unexpected default font is displayed using setFont() :

Image

Java version Same issue and fix tested on jdk11, jdk17, jdk23.

ron190 avatar Jan 23 '25 12:01 ron190

Hmm, I can't reproduce this, at least on Windows 10 + Java 17.

To eliminate it being a property of the specific font somehow - I tested with this one.

SSCCE:

package org.fife.ui.rsyntaxtextarea.demo;

import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rtextarea.RTextScrollPane;

import javax.swing.*;
import java.awt.*;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

public final class RSyntaxTextAreaDemoApp2 extends JFrame {

	private RSyntaxTextAreaDemoApp2() {

		RSyntaxTextArea textArea = new RSyntaxTextArea(25, 60);
		textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL);

		try {
			GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
			InputStream fontStream = new BufferedInputStream(
				Files.newInputStream(Paths.get("D:/temp/UbuntuMono-R.ttf"))
			);
			Font newFont = Font.createFont(Font.TRUETYPE_FONT, fontStream);
			graphicsEnvironment.registerFont(newFont);
			textArea.setFont(new Font("Ubuntu Mono", Font.PLAIN, 14));//newFont);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}

		textArea.setText("Using font: " + textArea.getFont().getFamily() + "\n\n" +
			"http://localhost:8080 abcdefghijklmnopqrstuvwxyz");

		RTextScrollPane scrollPane = new RTextScrollPane(textArea);
		setContentPane(scrollPane);
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		setTitle("RSyntaxTextArea Demo Application");
		pack();
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(() -> {
			try {
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			} catch (Exception e) {
				e.printStackTrace(); // Never happens
			}
			Toolkit.getDefaultToolkit().setDynamicLayout(true);
			new RSyntaxTextAreaDemoApp2().setVisible(true);
		});
	}
}

Produces this output (the font doesn't look great, but the individual glyphs look like those in your "expected screenshot?):

Without loading the font With loading the font
Image Image

@ron190 can you provide the OS, exact font TTF file, and any other info that might help narrow things down?

bobbylight avatar Feb 08 '25 15:02 bobbylight

Based on your SSCCE, I manage to reproduce the font reset behavior on 2 different ways :

  • either I set a theme after having set the font
  • or I update the UI after having set the font

I'm facing these behaviors as my app can switch theme at runtime when font is already set 😅

Way 1: When font is set, setting a theme is resetting to default font

textArea.setFont(new Font("Ubuntu Mono", Font.PLAIN, 14));//newFont);  👈 
Theme theme = Theme.load(
  RSyntaxTextAreaDemoApp2.class.getResourceAsStream("/org/fife/ui/rsyntaxtextarea/themes/dark.xml")
);
theme.apply(textArea);

Image

Setting theme before the font displays expected font :

Theme theme = Theme.load(
  RSyntaxTextAreaDemoApp2.class.getResourceAsStream("/org/fife/ui/rsyntaxtextarea/themes/dark.xml")
);
theme.apply(textArea);
textArea.setFont(new Font("Ubuntu Mono", Font.PLAIN, 14));//newFont);  👈 

Image

Way 2: When font is set, updating the UI is resetting to default font

Issue displays here :

new RSyntaxTextAreaDemoApp2().setVisible(true);  👈
for (Window w: Window.getWindows()) {
  SwingUtilities.updateComponentTreeUI(w);
}

No issue :

for (Window w: Window.getWindows()) {
  SwingUtilities.updateComponentTreeUI(w);
}
new RSyntaxTextAreaDemoApp2().setVisible(true);  👈

ron190 avatar Feb 08 '25 18:02 ron190

Gotcha! Reproducible now.

It may not have been the best decision, or the most intuitive, but applying a new theme always resets the font to the editor default, unless you use the load() overload that configure the Theme font:

Theme theme = Theme.load(in, textArea.getFont());
theme.apply(textArea);

That should solve your "Way 1."

I can't reproduce with your Way 2 though, and it shouln't change when updating the UI, unless you use a FontUIResource instead of a Font. Can you confirm whether you're doing that?

SSCCE with updateComponentTreeUI:
package org.fife.ui.rsyntaxtextarea.demo;

import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rsyntaxtextarea.Theme;
import org.fife.ui.rtextarea.RTextScrollPane;

import javax.swing.*;
import java.awt.*;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

public final class RSyntaxTextAreaDemoApp2 extends JFrame {

	private RSyntaxTextAreaDemoApp2() {

		RSyntaxTextArea textArea = new RSyntaxTextArea(25, 60);
		textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL);

		try {
			GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
			InputStream fontStream = new BufferedInputStream(
				Files.newInputStream(Paths.get("/Users/robert/Downloads/UbuntuMono-R.ttf"))
			);
			Font newFont = Font.createFont(Font.TRUETYPE_FONT, fontStream);
			graphicsEnvironment.registerFont(newFont);
			textArea.setFont(new Font("Ubuntu Mono", Font.PLAIN, 14));//newFont);

//			Theme theme = Theme.load(
//				RSyntaxTextAreaDemoApp2.class.getResourceAsStream("/org/fife/ui/rsyntaxtextarea/themes/dark.xml")
//			);
//			theme.apply(textArea);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}

		textArea.setText("Using font: " + textArea.getFont().getFamily() + "\n\n" +
			"http://localhost:8080 abcdefghijklmnopqrstuvwxyz");

		RTextScrollPane scrollPane = new RTextScrollPane(textArea);
		setContentPane(scrollPane);
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		setTitle("RSyntaxTextArea Demo Application");
		pack();
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(() -> {
			try {
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			} catch (Exception e) {
				e.printStackTrace(); // Never happens
			}
			Toolkit.getDefaultToolkit().setDynamicLayout(true);
			new RSyntaxTextAreaDemoApp2().setVisible(true);

			for (Window w: Window.getWindows()) {
				SwingUtilities.updateComponentTreeUI(w);
			}
		});
	}
}

bobbylight avatar Feb 17 '25 02:02 bobbylight

Links just for reference to the legacy code, as I don't know if I use FontUIResource or not, I tried something similar to :

But it still not loads the custom font, though I suppose it reveals there's a 3rd way that's not loading the custom font :

Way 3: When loading custom font by UIManager.put(), default font shows

SSCCE with UIManager.put() working on JTextArea, but not working on RSyntaxTextArea
package com.jsql.view.swing;

import com.jsql.view.swing.util.UiUtil;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rsyntaxtextarea.Theme;
import org.fife.ui.rtextarea.RTextScrollPane;

import javax.swing.*;
import java.awt.*;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Objects;

public final class RSyntaxTextAreaDemoApp2 extends JFrame {

    private RSyntaxTextAreaDemoApp2() {

        RSyntaxTextArea textArea = new RSyntaxTextArea(25, 60);
        textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL);

        try {
            GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
            InputStream fontStream = new BufferedInputStream(
//                    Files.newInputStream(Paths.get("swing/font/UbuntuMono-R-ctrlchar.ttf"))
                    Objects.requireNonNull(UiUtil.class.getClassLoader().getResourceAsStream("swing/font/UbuntuMono-R-ctrlchar.ttf"))
            );
            Font newFont = Font.createFont(Font.TRUETYPE_FONT, fontStream);
            graphicsEnvironment.registerFont(newFont);
//            textArea.setFont(new Font("Ubuntu Mono", Font.PLAIN, 14));//newFont);

            UIManager.put("TextArea.font", newFont.deriveFont(24f));

//			Theme theme = Theme.load(
//				RSyntaxTextAreaDemoApp2.class.getResourceAsStream("/org/fife/ui/rsyntaxtextarea/themes/dark.xml")
//			);
//			theme.apply(textArea);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        textArea.setText("Using font: " + textArea.getFont().getFamily() + "\n\n" +
                "http://localhost:8080 abcdefghijklmnopqrstuvwxyz");

        RTextScrollPane scrollPane = new RTextScrollPane(textArea);
//        setContentPane(scrollPane);
        setContentPane(new JScrollPane(new JTextArea("azeaz 0123456789 0000")));
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setTitle("RSyntaxTextArea Demo Application");
        pack();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception e) {
                e.printStackTrace(); // Never happens
            }
            Toolkit.getDefaultToolkit().setDynamicLayout(true);
            new RSyntaxTextAreaDemoApp2().setVisible(true);

//            for (Window w: Window.getWindows()) {
//                SwingUtilities.updateComponentTreeUI(w);
//            }
        });
    }
}

Also for reference, the SSCCEs for the 2 other ways:

Way 1: When font is set, setting a theme is resetting to default font
package com.jsql.view.swing;

import com.jsql.view.swing.util.UiUtil;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rsyntaxtextarea.Theme;
import org.fife.ui.rtextarea.RTextScrollPane;

import javax.swing.*;
import java.awt.*;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Objects;

public final class RSyntaxTextAreaDemoApp2 extends JFrame {

    private RSyntaxTextAreaDemoApp2() {

        RSyntaxTextArea textArea = new RSyntaxTextArea(25, 60);
        textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL);

        try {
            GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
            InputStream fontStream = new BufferedInputStream(
//                    Files.newInputStream(Paths.get("swing/font/UbuntuMono-R-ctrlchar.ttf"))
                    Objects.requireNonNull(UiUtil.class.getClassLoader().getResourceAsStream("swing/font/UbuntuMono-R-ctrlchar.ttf"))
            );
            Font newFont = Font.createFont(Font.TRUETYPE_FONT, fontStream);
            graphicsEnvironment.registerFont(newFont);
            textArea.setFont(new Font("Ubuntu Mono", Font.PLAIN, 14));//newFont);

//            UIManager.put("TextArea.font", newFont.deriveFont(24f));

			Theme theme = Theme.load(
				RSyntaxTextAreaDemoApp2.class.getResourceAsStream("/org/fife/ui/rsyntaxtextarea/themes/dark.xml")
			);
			theme.apply(textArea);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        textArea.setText("Using font: " + textArea.getFont().getFamily() + "\n\n" +
                "http://localhost:8080 abcdefghijklmnopqrstuvwxyz");

        RTextScrollPane scrollPane = new RTextScrollPane(textArea);
        setContentPane(scrollPane);
//        setContentPane(new JScrollPane(new JTextArea("azeaz 0123456789 0000")));
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setTitle("RSyntaxTextArea Demo Application");
        pack();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception e) {
                e.printStackTrace(); // Never happens
            }
            Toolkit.getDefaultToolkit().setDynamicLayout(true);
            new RSyntaxTextAreaDemoApp2().setVisible(true);

//            for (Window w: Window.getWindows()) {
//                SwingUtilities.updateComponentTreeUI(w);
//            }
        });
    }
}
Way 2: When font is set, updating the UI is resetting to default font
package com.jsql.view.swing;

import com.jsql.view.swing.util.UiUtil;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rsyntaxtextarea.Theme;
import org.fife.ui.rtextarea.RTextScrollPane;

import javax.swing.*;
import java.awt.*;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Objects;

public final class RSyntaxTextAreaDemoApp2 extends JFrame {

    private RSyntaxTextAreaDemoApp2() {

        RSyntaxTextArea textArea = new RSyntaxTextArea(25, 60);
        textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL);

        try {
            GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
            InputStream fontStream = new BufferedInputStream(
//                    Files.newInputStream(Paths.get("swing/font/UbuntuMono-R-ctrlchar.ttf"))
                    Objects.requireNonNull(UiUtil.class.getClassLoader().getResourceAsStream("swing/font/UbuntuMono-R-ctrlchar.ttf"))
            );
            Font newFont = Font.createFont(Font.TRUETYPE_FONT, fontStream);
            graphicsEnvironment.registerFont(newFont);
            textArea.setFont(new Font("Ubuntu Mono", Font.PLAIN, 14));//newFont);

//            UIManager.put("TextArea.font", newFont.deriveFont(24f));

//			Theme theme = Theme.load(
//				RSyntaxTextAreaDemoApp2.class.getResourceAsStream("/org/fife/ui/rsyntaxtextarea/themes/dark.xml")
//			);
//			theme.apply(textArea);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        textArea.setText("Using font: " + textArea.getFont().getFamily() + "\n\n" +
                "http://localhost:8080 abcdefghijklmnopqrstuvwxyz");

        RTextScrollPane scrollPane = new RTextScrollPane(textArea);
        setContentPane(scrollPane);
//        setContentPane(new JScrollPane(new JTextArea("azeaz 0123456789 0000")));
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setTitle("RSyntaxTextArea Demo Application");
        pack();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception e) {
                e.printStackTrace(); // Never happens
            }
            Toolkit.getDefaultToolkit().setDynamicLayout(true);
            new RSyntaxTextAreaDemoApp2().setVisible(true);

            for (Window w: Window.getWindows()) {
                SwingUtilities.updateComponentTreeUI(w);
            }
        });
    }
}

ron190 avatar Feb 17 '25 21:02 ron190