Search code examples
javaswinglook-and-feeljtextpaneantialiasing

Alloy Look and Feel and Anti-Aliasing


Anyone here using the Alloy Look and Feel? I'm facing a strange bug with anti-aliasing and JTextComponents. Alloy by default does not use anti-aliasing at all, so I have to force it by creating my own UI-classes. This works fine in most cases, but there are certain characters that wreak havoc to anti-aliasing.

For example, if the Alloy is set as a Look and Feel, and I insert some Hebrew text into a JTextComponent, e.g: שלום, מה שלומך שמי הוא האקזיד', the WHOLE JTextComponent suddenly loses anti-aliasing - permanently.

The strange thing is that I do not even extend the AlloyTextPaneUI, but BasicTextPaneUI to do the anti-aliasing, so I am puzzled where the Alloy comes into the picture (other Look and Feels appear to work just fine).

I am having very hard time tracing this bug... Anyone faced the same issue?

Here's a short example demonstrating the problem:

import com.incors.plaf.alloy.AlloyLookAndFeel;
import com.incors.plaf.alloy.themes.glass.GlassTheme;

import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicTextPaneUI;
import javax.swing.text.BadLocationException;
import javax.swing.text.StyledDocument;
import java.awt.*;

public class Scrap {

    static {
        // NOTE: You need a license code for Alloy!
        AlloyLookAndFeel.setProperty("alloy.licenseCode", "your license here");

        UIManager.put("TextPaneUI", MyTextPaneUI.class.getName());

        try {
            UIManager.setLookAndFeel(new AlloyLookAndFeel(new GlassTheme()));
        } catch (UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }

        // With system Look and Feel everything works just fine...
//      try {
//          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
//      } catch (ClassNotFoundException e) {
//          e.printStackTrace();
//      } catch (InstantiationException e) {
//          e.printStackTrace();
//      } catch (IllegalAccessException e) {
//          e.printStackTrace();
//      } catch (UnsupportedLookAndFeelException e) {
//          e.printStackTrace();
//      }
    }

    public static void main(final String args[]) {
        JTextPane text = new JTextPane();

        text.setFont(new Font("Monospaced", Font.PLAIN, 14));

        StyledDocument doc = text.getStyledDocument();

        try {

            doc.insertString(doc.getLength(), "Here's some regular text. Nice and smooth with anti-aliasing.\n\n", null);

            doc.insertString(doc.getLength(), "Here's some more text Blaa Blaa Blaaa. Lorem ipsum... now try to uncomment the Hebrew text.\n\n", null);

            // Try to uncomment this line and the anti-aliasing breaks for the whole JTextPane
//          doc.insertString(doc.getLength(), "שלום, מה שלומך שמי הוא האקזידן\n\n", null);

            // Here's another strange glyph that breaks the anti-aliasing
//          doc.insertString(doc.getLength(), "ಠ", null);

        } catch (BadLocationException e) {
            e.printStackTrace();
        }

        JFrame frame = new JFrame();

        JScrollPane scroll = new JScrollPane();
        scroll.setViewportView(text);
        scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        frame.add(scroll, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(600, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static class MyTextPaneUI extends BasicTextPaneUI {

        @Override
        protected void paintSafely(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(
                            RenderingHints.KEY_TEXT_ANTIALIASING,
                            RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
            super.paintSafely(g);
        }

        public static ComponentUI createUI(JComponent c) {
            return new MyTextPaneUI();
        }
    }
}

Solution

  • After some very frustrating experimentation I got it fixed.. I'm still not sure what exactly caused it but here's how I fixed it. There is apparently a key missing/broken in the UIDefaults in Alloy (I don't know which one). So I added all the defaults from the initial Look and Feel to the Alloy properties. This is kind of a quick and dirty solution (only problem I had was that the menus became non-opaque), but it's good enough for my needs. Maybe someone else finds it helpful as well.

    AlloyLookAndFeel laf = new AlloyLookAndFeel(theme) {
        @Override
        public UIDefaults getDefaults() {
            UIDefaults defs = new UIDefaults();
    
            defs.putAll(UIManager.getLookAndFeelDefaults());
    
            initClassDefaults(defs);
            initSystemColorDefaults(defs);
            initComponentDefaults(defs);
    
            defs.put("Menu.opaque", true);
    
            return defs;
        }
    };