pre*_*edi 9 java swing jtextcomponent
最近我注意到Java文本组件使用换行符(LF \n,, 0x0A)来在内部表示和解释换行符.这让我感到非常惊讶,并提出我的假设,在System.getProperty('line.separator') 任何地方使用都是一个很好的做法,在问号下.
看来,无论何时处理文本组件,在使用提到的属性时都应该非常小心,因为如果使用JTextComponent.setText(String),最终可能会得到一个包含不可见换行符的组件(例如CR).除非可以将文本组件的内容保存到文件中,否则这可能看起来不那么重要.如果使用所有文本组件提供的方法将文本保存并打开到文件,则在重新打开文件时,隐藏的换行符会突然显示在组件中.原因似乎是该JTextComponent.read(...)方法进行了规范化.
那么为什么不JTextComponent.setText(String)规范化线路结束?或者是否允许在文本组件中修改文本的任何其他方法?System.getProperty('line.separator')处理文本组件时是否使用了良好的做法?这是一个好习惯吗?
一些代码将这个问题放到透视中:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class TextAreaTest extends JFrame {
private JTextArea jtaInput;
private JScrollPane jscpInput;
private JButton jbSaveAndReopen;
public TextAreaTest() {
super();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("Text Area Test");
GridBagLayout layout = new GridBagLayout();
setLayout(layout);
jtaInput = new JTextArea();
jtaInput.setText("Some text followed by a windows newline\r\n"
+ "and some more text.");
jscpInput = new JScrollPane(jtaInput);
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = 0; constraints.gridy = 0;
constraints.gridwidth = 2;
constraints.weightx = 1.0; constraints.weighty = 1.0;
constraints.fill = GridBagConstraints.BOTH;
add(jscpInput, constraints);
jbSaveAndReopen = new JButton(new SaveAndReopenAction());
constraints = new GridBagConstraints();
constraints.gridx = 1; constraints.gridy = 1;
constraints.anchor = GridBagConstraints.EAST;
constraints.insets = new Insets(5, 0, 2, 2);
add(jbSaveAndReopen, constraints);
pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TextAreaTest tat = new TextAreaTest();
tat.setVisible(true);
}
});
}
private class SaveAndReopenAction extends AbstractAction {
private File file = new File("text-area-test.txt");
public SaveAndReopenAction() {
super("Save and Re-open");
}
private void saveToFile()
throws UnsupportedEncodingException, FileNotFoundException,
IOException {
Writer writer = null;
try {
writer = new OutputStreamWriter(
new FileOutputStream(file), "UTF-8");
TextAreaTest.this.jtaInput.write(writer);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException ex) {
}
}
}
}
private void openFile()
throws UnsupportedEncodingException, IOException {
Reader reader = null;
try {
reader = new InputStreamReader(
new FileInputStream(file), "UTF-8");
TextAreaTest.this.jtaInput.read(reader, file);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
}
}
}
}
public void actionPerformed(ActionEvent e) {
Throwable exc = null;
try {
saveToFile();
openFile();
} catch (UnsupportedEncodingException ex) {
exc = ex;
} catch (FileNotFoundException ex) {
exc = ex;
} catch (IOException ex) {
exc = ex;
}
if (exc != null) {
JOptionPane.showConfirmDialog(
TextAreaTest.this, exc.getMessage(), "An error occured",
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
添加新文本后,此程序在我的Windows机器上保存的示例(为什么单个CR?o_O):

Edit01
我在Netbeans IDE中运行/调试了这个,它在Windows 7上使用JDK1.7u15 64位(C:\ Program Files\Java\jdk1.7.0_15).
首先,真正的答案是设计师认为设计应该如此。您确实需要询问他们以了解真正的原因。
话说回来:
那么为什么 JTextComponent.setText(String) 不规范行结尾呢?
我认为最有可能的原因是:
这将是意想不到的行为。大多数程序员希望1文本字段上的“get”返回与“set”或用户输入的字符串值相同的字符串值。
如果文本字段确实标准化,那么程序员将很难将原始文本的行结尾保留在花瓶中,而这是需要的。
设计者可能想在某个时候改变他们的想法(参见read和write方法的报告行为),但由于兼容性原因而无法改变。
无论如何,如果您需要标准化,没有什么可以阻止您的代码对 setter 检索到的值执行此操作。
或者任何其他允许在文本组件内修改文本的方法?
据报道(见评论)read和/或write进行标准化。
处理文本组件时使用 System.getProperty('line.separator') 是一个好习惯吗?这是一个好的做法吗?
这取决于上下文。如果您知道您正在读取和写入要在“此”平台上处理的文件,这可能是个好主意。如果文件打算在不同的平台上(使用不同的行分隔符)读取,那么规范化以匹配当前机器的约定可能是一个坏主意。
read1 - 其他方法如和writethat 的行为可能不同这一事实不会影响这一点。他们不是“getter”和“setter”。我说的是人们期望“getters”和“setters”的行为方式......而不是其他任何东西。此外,人们不应该期望一切都以相同的方式运行,除非明确规定它们这样做。但显然,这里的问题在于规范……javadocs……对这些问题保持沉默。
另一种可能性是 @predi 报告的规范化行为实际上发生在Reader/Writer对象中......