Search code examples
javaswingsubstance

HighlightPainter issue with Substance UI when using Monospaced font


I am using Highlighter.HighlightPainter interface for highlighting the lines of a text area. I used the source code from this website: Line Painter. It works just great, but when I used org.jvnet.substance.skin.SubstanceBusinessBlackSteelLookAndFeel for decorating the GUI, an issue comes up. Whenever I change the font of the text area to Monospaced, the paint() method of Highlighter.HighlightPainter isn't invoked for some reason. Here is a sample code:

import java.awt.Font;
import java.awt.Graphics;
import java.awt.Shape;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.text.BadLocationException;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;

public class TestFrame extends JFrame implements Highlighter.HighlightPainter
{
    private static final long serialVersionUID = 1L;

    static
    {
        try
        {
            JFrame.setDefaultLookAndFeelDecorated(true);
            JDialog.setDefaultLookAndFeelDecorated(true);
            UIManager.setLookAndFeel(new org.jvnet.substance.skin.SubstanceBusinessBlackSteelLookAndFeel()); 
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    public TestFrame() throws BadLocationException
    {
        super("The title");
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        JTextArea txt = new JTextArea(10, 30);
        txt.getHighlighter().addHighlight(0, 0, this);
        txt.setFont(new Font("Monospaced", Font.PLAIN, 12));
        JPanel container = (JPanel) getContentPane();
        container.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        container.add(txt);
        pack();
        setLocationRelativeTo(null);
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    new TestFrame().setVisible(true);
                }
                catch(BadLocationException e)
                {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c)
    {
        System.out.println("paint() is invoked!");
    }
}

If I comment this line:

txt.setFont(new Font("Monospaced", Font.PLAIN, 12));

paint() will be invoked. Is there anyway to fix this issue?


Solution

  • 1) @Eng.Fouad this was n_times mentioned (@camickr, @StanislavL) here for styled and highligted test use JTextComponent that supporting that

    2) @Eng.Fouad you are right output from JTextArea

    enter image description here enter image description here

    from code

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.text.*;
    
    public class TextPaneHighlighting {
    
        private static final long serialVersionUID = 1L;
        private Highlighter.HighlightPainter cyanPainter;
        private Highlighter.HighlightPainter redPainter;
    
        public TextPaneHighlighting() {
            JFrame frame = new JFrame();
            JTextPane textPane = new JTextPane();
            textPane.setText("one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\n");
            //textPane.setFont(new Font("Monospaced", Font.PLAIN, 12)); // uncommnent
            JScrollPane scrollPane = new JScrollPane(textPane);
            frame.add(scrollPane, BorderLayout.CENTER);//  Highlight some text
            cyanPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.cyan);
            redPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.red);
            try {
                textPane.getHighlighter().addHighlight(0, 3, DefaultHighlighter.DefaultPainter);
                textPane.getHighlighter().addHighlight(8, 14, cyanPainter);
                textPane.getHighlighter().addHighlight(19, 24, redPainter);
            } catch (BadLocationException ble) {
            }
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setPreferredSize(new Dimension(300, 200));
            frame.setLocationRelativeTo(null);
            frame.pack();
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    JFrame.setDefaultLookAndFeelDecorated(true);
                    JDialog.setDefaultLookAndFeelDecorated(true);
                    try {
                        UIManager.setLookAndFeel(new org.pushingpixels.substance.api.skin.SubstanceBusinessBlackSteelLookAndFeel());
                    } catch (UnsupportedLookAndFeelException ex) {
                    }
                    TextPaneHighlighting tph = new TextPaneHighlighting();
                }
            });
        }
    }
    

    3) as @ trashgod correctly mentioned never to set whatever in Substance without invokeLater, never, whatever Look and Feel sensitive, right maybe in this moment Font isn't important, maybe not

    4) simple JTextArea have got some issue with Font and Look and Feel, maybe there are own Highlighter concept as for Renderer (sorry I lazy read API after wake_up) and Substance, for Renderer concept you must to use SubstanceRenderer instead of XxxRenderer, then all formatting wokrs as you excepted

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.text.*;
    
    public class Fonts implements Runnable {
    
        private String[] fnt;
        private JFrame frm;
        private JScrollPane jsp;
        private JTextPane jta;
        private int width = 450;
        private int height = 300;
        private GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        private StyledDocument doc;
        private MutableAttributeSet mas;
        private int cp = 0;
        private Highlighter.HighlightPainter cyanPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.cyan);
        private Highlighter.HighlightPainter redPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.red);
        private Highlighter.HighlightPainter whitePainter = new DefaultHighlighter.DefaultHighlightPainter(Color.white);
        private int _count = 0;
        private int _lenght = 0;
    
        public Fonts() {
            jta = new JTextPane();
            doc = jta.getStyledDocument();
            jsp = new JScrollPane(jta);
            jsp.setPreferredSize(new Dimension(height, width));
            frm = new JFrame("awesome");
            frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frm.setLayout(new BorderLayout());
            frm.add(jsp, BorderLayout.CENTER);
            frm.setLocation(100, 100);
            frm.pack();
            frm.setVisible(true);
            jta.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            fnt = ge.getAvailableFontFamilyNames();
            mas = jta.getInputAttributes();
            new Thread(this).start();
        }
    
        @Override
        public void run() {
            for (int i = 0; i < fnt.length; i++) {
                StyleConstants.setBold(mas, false);
                StyleConstants.setItalic(mas, false);
                StyleConstants.setFontFamily(mas, fnt[i]);
                StyleConstants.setFontSize(mas, 16);
                dis(fnt[i]);
                try {
                    Thread.sleep(75);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                StyleConstants.setBold(mas, true);
                dis(fnt[i] + " Bold");
                try {
                    Thread.sleep(75);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                StyleConstants.setItalic(mas, true);
                dis(fnt[i] + " Bold & Italic");
                try {
                    Thread.sleep(75);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                StyleConstants.setBold(mas, false);
                dis(fnt[i] + " Italic");
                try {
                    Thread.sleep(75);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            jta.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        }
    
        public void dis(String s) {
            _count++;
            _lenght = jta.getText().length();
            try {
                doc.insertString(cp, s, mas);
                doc.insertString(cp, "\n", mas);
            } catch (Exception bla_bla_bla_bla) {
                bla_bla_bla_bla.printStackTrace();
            }
            if (_count % 2 == 0) {
                try {
                    jta.getHighlighter().addHighlight(1, _lenght - 1, cyanPainter);
                } catch (BadLocationException bla_bla_bla_bla) {
                }
            } else if (_count % 3 == 0) {
                try {
                    jta.getHighlighter().addHighlight(1, _lenght - 1, redPainter);
                } catch (BadLocationException bla_bla_bla_bla) {
                }
            } else {
                try {
                    jta.getHighlighter().addHighlight(1, _lenght - 1, whitePainter);
                } catch (BadLocationException bla_bla_bla_bla) {
                }
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    JFrame.setDefaultLookAndFeelDecorated(true);
                    JDialog.setDefaultLookAndFeelDecorated(true);
                    try {
                        UIManager.setLookAndFeel(new org.pushingpixels.substance.api.skin.SubstanceBusinessBlackSteelLookAndFeel());
                    } catch (UnsupportedLookAndFeelException ex) {
                    }
                    Fonts fs = new Fonts();
                }
            });
        }
    }