Java Swing-My类扩展了JTextPane,并首先调用My append(),然后调用super.setText()添加额外的换行符

Java Swing-My类扩展了JTextPane,并首先调用My append(),然后调用super.setText()添加额外的换行符,java,swing,jtextpane,Java,Swing,Jtextpane,很简单:我有一个SSCCE: import java.io.File; import javax.swing.JFrame; import javax.swing.JTextPane; import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.MutableAttributeS

很简单:我有一个SSCCE:

import java.io.File;

import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

import net.miginfocom.swing.MigLayout;

public class Test1_ChangeStyleAndAppend extends JFrame {
    public class MyJTextPane extends JTextPane {
        /**
         * Append some text to this pane.
         * @param s
         */
        public void append(String s) {
            try {
               Document doc = this.getDocument();
               doc.insertString(doc.getLength(), s, null);
            } catch(BadLocationException e) {
                System.err.println(e);
            }
        }

        /**
         * Append some text and change line.
         * @param s
         */
        public void appendLine(String s) {
            try {
                Document doc = this.getDocument();
                doc.insertString(doc.getLength(), s + System.lineSeparator(), null);
            } catch(BadLocationException e) {
                System.err.println(e);
            }
        }
    }
    public Test1_ChangeStyleAndAppend() {
        begin();
    }

    private void begin() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        MyJTextPane pane0 = new MyJTextPane();
        pane0.appendLine("MyJTextPane using append() and then calling setText()");
        pane0.appendLine("Second line. ");
        pane0.appendLine("Third line");
        pane0.setText(pane0.getText() + "At last" + System.lineSeparator());
        pane0.setBorder(new EtchedBorder(EtchedBorder.RAISED));
        add(pane0, BorderLayout.NORTH);

        MyJTextPane pane = new MyJTextPane();
//        changeLineSpacing(pane, 1.5f, false);
        pane.appendLine("MyJTextPane calling appendLine()");
        pane.appendLine("Second line. ");
        pane.appendLine("Third line");
        pane.appendLine("At last");
        pane.setBorder(new EtchedBorder(EtchedBorder.RAISED));
        add(pane, BorderLayout.CENTER);


        JTextPane pane2 = new JTextPane();
        pane2.setText("Normal JTextPane calling setText()");
        pane2.setText(pane2.getText() + System.lineSeparator() + "Second line. ");
        pane2.setText(pane2.getText() + System.lineSeparator() + "Third line");
        pane2.setText(pane2.getText() + System.lineSeparator() + "At last");
        pane2.setBorder(new EtchedBorder(EtchedBorder.RAISED));
        add(pane2, BorderLayout.SOUTH);

        pack();
        setVisible(true);
    }

    /**
     * Select all the text of a <code>JTextPane</code> first and then set the line spacing.
     * @param pane the <code>JTextPane</code> to apply the change
     * @param factor the factor of line spacing. For example, <code>1.0f</code>.
     * @param replace whether the new <code>AttributeSet</code> should replace the old set. If set to <code>false</code>, will merge with the old one.
     */
    public static void changeLineSpacing(JTextPane pane, float factor, boolean replace) {
        pane.selectAll();
        MutableAttributeSet set = new SimpleAttributeSet(pane.getParagraphAttributes());
        StyleConstants.setLineSpacing(set, factor);
        pane.setParagraphAttributes(set, replace);
        pane.setCaretPosition(0); //scroll to the top.
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                Test1_ChangeStyleAndAppend frame = new Test1_ChangeStyleAndAppend();

            }

        });
    }
}
结果是:

我喜欢窗户

我有两个文本窗格,一个是
JTextPane
,另一个是我的类扩展
JTextPane
,在这一个中,我在自定义类中定义了两个方便的方法,
append()
appendLine()
,但我没有覆盖super
getText()
方法

现在,当我在类中调用
appendLine()
然后调用
setText()
时,调用
getText()
会在行之间添加另一个
\r
,使其
\r\n
并在两行之间添加额外的空行。这不是我想要的,我不想添加
\r

我有一个类型为
JTextArea
的变量,为了更改行距,我将其更改为
JTextPane
,因为
JTextArea
不能有可调整的行距。但是它在整个项目中以及在使用
pane.setText(pane.getText+newText)
时都会出现。现在我必须搜索所有出现的
setText()
,并将其更改为
appendLine()
。在做这个大的改变之前,我想了解为什么要添加这个额外的
\r

如果我总是调用
append()
或总是调用
setText(pane.getText()+newText)
,则不会发生这种情况。但是如果我先调用
append()
,然后调用
setText(pane.getText()+newText)
,就会添加
\r


有人对此进行了说明?

Windows的行分隔符为“\r\n”

文档仅对新行字符串使用“\n”

//doc.insertString(doc.getLength(), s + System.lineSeparator(), null);
doc.insertString(doc.getLength(), s + "\n", null);
不确定到底是什么问题,但在insertString(…)和getText()方法之间,换行符字符串的处理方式存在不一致之处

简单的解决方案是使用其新行字符串更新文档,而不是平台换行字符串

//doc.insertString(doc.getLength(), s + System.lineSeparator(), null);
doc.insertString(doc.getLength(), s + "\n", null);

编辑:错误报告和存档。仅在Windows中发生。我使用Windows 10

上一个答案之所以被接受,是因为我已经多次接受我的答案,以此来解决我的问题:)是时候向别人表示一些慷慨了,这样我们才能继续互相帮助

=========================================================================

最后,当我触摸下面的文档时,我认为问题出现了。我猜,这是因为
JTextPane
使用StringWriter获取其内容,但这是错误的。在JDK 8u111源代码中,我发现:

/**
 * Returns the text contained in this <code>TextComponent</code>
 * in terms of the
 * content type of this editor.  If an exception is thrown while
 * attempting to retrieve the text, <code>null</code> will be returned.
 * This is implemented to call <code>JTextComponent.write</code> with
 * a <code>StringWriter</code>.
 *
 * @return the text
 * @see #setText
 */
public String getText() {
    String txt;
    try {
        StringWriter buf = new StringWriter();
        write(buf);
        txt = buf.toString();
    } catch (IOException ioe) {
        txt = null;
    }
    return txt;
}
StringWriter
可能做了一些错误的事情来生成额外的
\r
。因为如果我用接触文档的方法覆盖此方法,问题就消失了,所有输出都正常,
\n
System.lineseparator()


我有这个SSCCE:
-那不是SSCCE。MigLayout不是JDK的一部分。没有理由使用第三方版面管理器,因为您的问题与版面管理器无关。只需使用GridLayout。您好,我没有理由,但是如果您将System.lineSeparator()替换为appendLine方法,您将在第一个和第二个texpane中获得相同的结果。抱歉@camickr我忘记了这一点。我会更改它。@JulienGauthier谢谢,但你说“将System.lineSeparator()`替换为我的方法”时,我不明白你的意思。你想说“去掉这部分”?我添加它是为了节省每次添加新行的工作量,这就是为什么它被称为
appendLine()
,以区别于
append()
。我在第二个面板中使用了
appendLine()
,并且没有添加额外的换行符…我已经编辑了问题以使用
BorderLayout
。我希望这能有所帮助,有人能帮上忙。提前谢谢。你说得对,谢谢卡米克。原因不得而知,但我看到了这一点:调用
pane.getText()
时,它使用
StringWriter buf=newstringwriter();写入(buf);txt=buf.toString()。这里可能就是问题发生的地方。如果我使用此代码获取文本:
请尝试{string=pane0.getDocument().getText(0,pane0.getDocument().getLength());}catch(BadLocationException e){e.printStackTrace();}
并将
“\n”
更改回
系统.lineSeparator()
,问题消失。错误报告给Oracle并等待。再次感谢。