当一行更改为更大的字体时,如何重绘JTextPane

时间:2013-11-01 17:57:40

标签: java swing jtextpane

我有JTextPane,其模型为DefaultStyledDocument。我注意到如果显示文本,然后我使用setCharacterAttributes将一行中的每个字符更改为更大的字体,那么该行上字符的字体会在我期望的显示中更改,但它下方的线条不会移动,因此线条在显示屏上重叠。

有没有办法强制JTextPane重新计算文本位置并重新显示自身(或其自身的一部分)?我尝试使用DocumentListener设置changedUpdate,确实调用了changedUpdate,但我无法找到重绘JTextPane的方法。 revalidate()没有用。

编辑:这些线路确实随着一个较小的测试用例自行移动,所以显然我在程序中正在做的其他事情是干扰,但我还没弄清楚是什么。无论如何,如果我无法确定导致问题的功能以及如何绕过它,repaint()没有revalidate()就可以正常工作。

编辑2:当JTextPane添加到JPanel并且JPanel设置为BoxLayoutBoxLayout.X_AXIS时,会出现问题。样本:

public class Demo extends JFrame {
    JPanel panel;
    JTextPane textPane;
    DefaultStyledDocument doc;

    SimpleAttributeSet smallText, bigText;

    public Demo() {
        super("Demo");
        doc = new DefaultStyledDocument ();
        textPane = new JTextPane(doc);
        panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
            // problem goes away if above line is removed
        panel.add(textPane);
        panel.setPreferredSize(new Dimension(1000, 500));
        textPane.setCaretPosition(0);
        textPane.setMargin(new Insets(5,5,5,5));
        getContentPane().add(panel, BorderLayout.CENTER);

        smallText = new SimpleAttributeSet();
        StyleConstants.setFontFamily(smallText, "SansSerif");
        StyleConstants.setFontSize(smallText, 16);

        bigText = new SimpleAttributeSet();
        StyleConstants.setFontFamily(bigText, "Times New Roman");
        StyleConstants.setFontSize(bigText, 32);

        initDocument();
        textPane.setCaretPosition(0);
    }

    protected void initDocument() {
        String initString[] =
                { "This is the first line.",
                  "This is the second line.",
                  "This is the third line." };

        for (int i = 0; i < initString.length; i ++) {
            try {
                doc.insertString(doc.getLength(), initString[i] + "\n",
                        smallText);
            } catch (BadLocationException e) {
            }
        }
    }

    private void createAndShowGUI() throws InterruptedException {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }

    public static void main(String[] args) throws Exception {
        new Demo().runMain();
    }

    private void runMain() throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                UIManager.put("swing.boldMetal", Boolean.FALSE);
                try {
                    createAndShowGUI();
                } catch (InterruptedException e) {
                }
            }
        });
        Thread.sleep(2000);
        doc.setCharacterAttributes(24, 24, bigText, false);
    }
}

2 个答案:

答案 0 :(得分:0)

调用repaint()它将重绘容器。 DocumentListener反映了对文本文档的更改,因此在您的情况下是不合适的。您可以使用DefaultStyledDocument.getStyle().addChangeListener()来处理属性的更改。

答案 1 :(得分:0)

我刚刚发现它也可以向setMinimumSize添加JTextPane来电:

        .......
        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
            // problem goes away if above line is removed
        panel.add(textPane);
        textPane.setMinimumSize(new Dimension(1000, 500));  // NEW
        // These also work:
        // textPane.setMinimumSize(new Dimension(1, 1));   or
        // textPane.setMinimumSize(new Dimension(0, 0));
        panel.setPreferredSize(new Dimension(1000, 500));
        textPane.setCaretPosition(0);
        .......

这比将JTextPane包裹在JScrollPane内的解决方案略胜一筹,因为即使没有显示滚动条,后者也会在边框附近显示一些额外的行。