Проблема HighlightPainter с пользовательским интерфейсом Substance при использовании моноширинного шрифта

Я использую интерфейс Highlighter.HighlightPainter для выделения строк текстовой области. Я использовал исходный код с этого сайта: Line Painter. Он отлично работает, но когда я использовал org.jvnet.substance.skin.SubstanceBusinessBlackSteelLookAndFeel для украшения графического интерфейса, возникает проблема. Всякий раз, когда я меняю шрифт текстовой области на Monospaced, метод paint() Highlighter.HighlightPainter по какой-то причине не вызывается. Вот пример кода:

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!");
    }
}

Если я прокомментирую эту строку:

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

paint() будет вызван. Есть ли способ исправить эту проблему?


person Eng.Fouad    schedule 11.05.2012    source источник
comment
В качестве отступления рассмотрим txt.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12)).   -  person trashgod    schedule 11.05.2012
comment
@trashgod спасибо за совет! Тем не менее Font.MONOSPACED возвращает "Monospaced" :)   -  person Eng.Fouad    schedule 11.05.2012
comment
Помогает ли это переместить UIManager.setLookAndFeel() из статического инициализатора перед EventQueue.invokeLater()?   -  person trashgod    schedule 11.05.2012
comment
@trashgod Ну, теперь это работает. Спасибо за советы :)   -  person Eng.Fouad    schedule 11.05.2012


Ответы (3)


1) @Eng.Fouad это было упомянуто n_times (@camickr, @StanislavL) здесь для стилизованного и выделенного теста используйте JTextComponent, который поддерживает это

2) @Eng.Fouad, вы правильно выводите из JTextArea

введите здесь описание изображениявведите здесь описание изображения

из кода

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) как правильно упомянул @ trashgod, никогда не устанавливайте что-либо в Substance без invokeLater, никогда, независимо от того, что чувствительно к внешнему виду и ощущениям, возможно, в этот момент шрифт не важен, а может и нет.

4) у простого JTextArea есть некоторые проблемы с Font и Look and Feel, возможно, есть собственная концепция Highlighter, как для Renderer (извините, я ленив читать API после wake_up) и Substance, для концепции Renderer вы должны использовать SubstanceRenderer вместо XxxRenderer, тогда все форматирование работы, как вы, за исключением

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();
            }
        });
    }
}
person mKorbel    schedule 11.05.2012

Что ж, для этого есть одно решение, создайте текстовую область и установите для нее шрифт непосредственно перед вызовом UIManager.setLookAndFeel().

person Eng.Fouad    schedule 11.05.2012

Просто для справки, вот быстрый тест LinePainter:

LinePainter

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;

/**
 * @see http://stackoverflow.com/q/10544046/230513
 * @see http://tips4java.wordpress.com/2008/10/29/line-painter/
 */
public class LinePainterTest extends JPanel {

    public LinePainterTest() {
        JTextPane textPane = new JTextPane();
        textPane.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 24));
        try {
            textPane.getDocument().insertString(0, "One\nTwo\nThree", null);
        } catch (BadLocationException ex) {
            ex.printStackTrace(System.err);
        }
        LinePainter painter = new LinePainter(textPane);
        this.add(textPane);
    }

    private void display() {
        JFrame f = new JFrame("LinePainterTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel(
            "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        JFrame.setDefaultLookAndFeelDecorated(true);
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new LinePainterTest().display();
            }
        });
    }
}
person trashgod    schedule 11.05.2012