我的字符串末尾的最终字符 '\n' 已被修改为 space 字符

final character '\n' at the end of my string has been modified to space character

我希望在 JTextField 中检索文本末尾的换行符,但是在将文本字段的文本设置为我的字符串后,它已被修改为 space特点。下面的代码突出了这个问题。

是否可以在文本字段中保留 \n

import javax.swing.JTextField;

public class StackOver {
    public static void main(String[] args) {
        String hasNewLineEscapeCharacter = makeStringWithNewLineCharacter();
        JTextField backgroundText = new JTextField(90);
        backgroundText.setText(hasNewLineEscapeCharacter);
        char spaceChar = backgroundText.getText().charAt(backgroundText.getText().length()-1);
        char newLineChar = hasNewLineEscapeCharacter.charAt(needsNewLineEscapeCharacter.length()-1);
    }

    public static String makeStringWithNewLineCharacter() {
        String str = "hello,world!";
        str += ('\n');
        return str;
    }       
}

Is it possible to preserve the '\n' in my JTextField?

A JTextField 使用一个 PlainDocument,其中包含一个 属性,过滤“\n”并将其替换为 space 字符。

要在文本字段中保留换行符,您可以尝试:

textField.getDocument().putProperty("filterNewlines", Boolean.FALSE);

但是,这会导致文本像文本区域一样分两行显示。

因此,按照上面的建议,您应该只使用 JTextArea。

无法在单行中显示包含换行符的文本。

您可能想要做的是在文本字符串中存储一些其他不可打印的字符,然后使用 String.replaceAll(...) 如果您需要访问添加回换行符的文本.

如果您希望 JTextField 在用户按下 [=] 时不仅 显示 ,而且 接受 换行符33=]输入键,还需要加一个ActionListener。如果您继承 JTextField(您可以使用 工厂方法 ),它可能看起来像这样:

public class JMultilineTextField extends JTextField {
    public JMultilineTextField() {
        addActionListener(e -> {
            try {
                final int selectionStart = getSelectionStart();
                final int selectionEnd = getSelectionEnd();

                final Document document = getDocument();
                if (selectionStart != selectionEnd) {
                    document.remove(selectionStart, selectionEnd - selectionStart);
                }
                document.insertString(selectionStart, "\n", null);
            } catch (final BadLocationException ble) {
                // Unlikely to happen, but add your error handling code here.
                ble.printStackTrace();
            }
        });
    }
}

但这带来了另一个问题:您的 JTextField 会随着换行符的添加或删除而垂直增长或收缩,您需要父组件反映文本字段大小的变化并相应地布局其子组件(否则,您很可能最终会有重叠的 Swing 组件)。这个问题可以通过在文本字段的 Document:

中安装 DocumentListener 来解决
public class JMultilineTextField extends JTextField {
    // ...

    @Override
    public void setDocument(final Document doc) {
        setupDocument(doc);

        super.setDocument(doc);
    }

    private void setupDocument(final Document doc) {
        doc.putProperty("filterNewlines", false);
        installDocumentListenerIfNecessary(doc);
    }

    private void installDocumentListenerIfNecessary(final Document doc) {
        final DocumentListener documentListeners[] = ((AbstractDocument) doc).getListeners(DocumentListener.class);
        if (Stream.of(documentListeners).noneMatch(documentListener -> documentListener instanceof RowCountChangeListener)) {
            doc.addDocumentListener(new RowCountChangeListener());
        }
    }

    private final class RowCountChangeListener implements DocumentListener {
        @Override
        public void insertUpdate(final DocumentEvent e) {
            revalidateParentIfNecessary();
        }

        @Override
        public void removeUpdate(final DocumentEvent e) {
            revalidateParentIfNecessary();
        }

        @Override
        public void changedUpdate(final DocumentEvent e) {
            revalidateParentIfNecessary();
        }

        private void revalidateParentIfNecessary() {
            final JMultilineTextField textField = JMultilineTextField.this;

            final Dimension currentSize = textField.getSize();
            final Dimension preferredSize = textField.getPreferredSize();

            /*
             * Grow/shrink vertically as necessary.
             */
            if (currentSize.height != preferredSize.height) {
                textField.getParent().revalidate();
            }
        }
    }
}

我还建议您从文本字段的构造函数中调用 setupDocument()

public class JMultilineTextField extends JTextField {
    public JMultilineTextField() {
        setupDocument(getDocument());

        // add ActionListener, etc.
    }

    // ...
}

Full code.