字符串末尾的最后一个字符'\ n'已修改为空格字符

时间:2018-07-17 02:38:27

标签: java swing newline jtextfield

我希望在JTextField中的文本末尾检索换行符,但是将文本字段的文本设置为我的字符串后,已将其修改为空格字符。下面的代码突出了问题所在。

是否可以在文本字段中保留\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;
    }       
}

2 个答案:

答案 0 :(得分:2)

  

是否可以在我的JTextField中保留'\ n'?

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

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

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

但是,这将导致文本像文本区域一样显示在两行上。

因此,如上所述,您应该只使用JTextArea。

无法在一行上显示包含换行符的文本。

您可能想做的是在文本字符串中存储其他无法打印的字符,然后如果需要访问带有换行符的文本,则使用String.replaceAll(...)。

答案 1 :(得分:0)

如果您希望 JTextField 不仅显示,而且在用户按下 Enter 键时接受 换行符,您还需要添加一个 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 组件)。可以通过在文本字段的 DocumentListener 中安装 Document 来解决此问题:

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