使JTextArea的部分不可编辑(不是整个JTextArea!)

我目前正在使用Swing的控制台窗口。 它基于JTextArea,就像一个常见的命令行。 在一行中键入命令,然后按Enter键。 在下一行中,显示输出,在该输出下,您可以编写下一个命令。

现在我想,你只能用你的命令编辑当前行。 上面的所有行(旧命令和结果)都应该是不可编辑的。 我怎样才能做到这一点?

您无需创建自己的组件。

这可以使用自定义DocumentFilter完成(就像我已经完成的那样)。

您可以从textPane.getDocument()获取文档,并通过document.setFilter()在其上设置filter。 在filter中,您可以检查提示位置,并且只有在位置在提示之后才允许修改。

例如:

 private class Filter extends DocumentFilter { public void insertString(final FilterBypass fb, final int offset, final String string, final AttributeSet attr) throws BadLocationException { if (offset >= promptPosition) { super.insertString(fb, offset, string, attr); } } public void remove(final FilterBypass fb, final int offset, final int length) throws BadLocationException { if (offset >= promptPosition) { super.remove(fb, offset, length); } } public void replace(final FilterBypass fb, final int offset, final int length, final String text, final AttributeSet attrs) throws BadLocationException { if (offset >= promptPosition) { super.replace(fb, offset, length, text, attrs); } } } 

但是,这会阻止您以编程方式将内容插入终端的输出(不可编辑)部分。 您可以做的是在您要添加输出时设置的filter上的直通标记,或者(我做了什么)在附加输出之前将文档filter设置为null,然后在您输出时重置它重做。

 import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.text.*; public class OnlyEditCurrentLineTest { public JComponent makeUI() { JTextArea textArea = new JTextArea(8,0); textArea.setText("> aaa\n> "); ((AbstractDocument)textArea.getDocument()).setDocumentFilter( new NonEditableLineDocumentFilter()); JPanel p = new JPanel(new BorderLayout()); p.add(new JScrollPane(textArea), BorderLayout.NORTH); return p; } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { createAndShowGUI(); } }); } public static void createAndShowGUI() { JFrame f = new JFrame(); f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.getContentPane().add(new OnlyEditCurrentLineTest().makeUI()); f.setSize(320,240); f.setLocationRelativeTo(null); f.setVisible(true); } } class NonEditableLineDocumentFilter extends DocumentFilter { @Override public void insertString( DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException { if(string == null) { return; }else{ replace(fb, offset, 0, string, attr); } } @Override public void remove( DocumentFilter.FilterBypass fb, int offset, int length) throws BadLocationException { replace(fb, offset, length, "", null); } private static final String PROMPT = "> "; @Override public void replace( DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { Document doc = fb.getDocument(); Element root = doc.getDefaultRootElement(); int count = root.getElementCount(); int index = root.getElementIndex(offset); Element cur = root.getElement(index); int promptPosition = cur.getStartOffset()+PROMPT.length(); //As Reverend Gonzo says: if(index==count-1 && offset-promptPosition>=0) { if(text.equals("\n")) { String cmd = doc.getText(promptPosition, offset-promptPosition); if(cmd.isEmpty()) { text = "\n"+PROMPT; }else{ text = "\n"+cmd+"\n xxxxxxxxxx\n" + PROMPT; } } fb.replace(offset, length, text, attrs); } } } 

AFAIK,你需要实现自己的控制

也许你可以用一个文本字段列表(甚至是启用和奇数禁用)或混合的文本字段/标签来模拟它

编辑:

我敢打赌一个不可编辑的textarea和一个可编辑的文本字段。 输入文本字段,按回车键,添加“命令”并输出到textarea

这是我在java中充当控制台的文档filter的实现。 但是,通过一些修改以允许我具有“命令区域”和“日志区域”,这意味着命令的结果在日志区域中打印并且实际命令在命令区域中打印。 日志区域只是另一个非可编辑的Jtext区域。 我发现这个线程是有用的,所以有人试图获得类似于这个实现的东西可以找到一些指针!

 class NonEditableLineDocumentFilter extends DocumentFilter { private static final String PROMPT = "Command> "; @Override public void insertString(DocumentFilter.FilterBypass fb, int offset, String string,AttributeSet attr) throws BadLocationException { if(string == null) { return; } else { replace(fb, offset, 0, string, attr); } } @Override public void remove(DocumentFilter.FilterBypass fb, int offset,int length) throws BadLocationException { replace(fb, offset, length, "", null); } @Override public void replace(DocumentFilter.FilterBypass fb, int offset, int length,String text, AttributeSet attrs) throws BadLocationException { Document doc = fb.getDocument(); Element root = doc.getDefaultRootElement(); int count = root.getElementCount(); int index = root.getElementIndex(offset); Element cur = root.getElement(index); int promptPosition = cur.getStartOffset()+PROMPT.length(); if(index==count-1 && offset-promptPosition>=0) { if(text.equals("\n")) { cmd = doc.getText(promptPosition, offset-promptPosition); if(cmd.trim().isEmpty()) { text = "\n"+PROMPT; } else { text = "\n" + PROMPT; } } fb.replace(offset, length, text, attrs); } } } 

那么,当“>>”是命令行中用户可以输入命令的每一行的开头时:

 textArea.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent event) { int code = event.getKeyCode(); int caret = textArea.getCaretPosition(); int last = textArea.getText().lastIndexOf(">> ") + 3; if(caret <= last) { if(code == KeyEvent.VK_BACK_SPACE) { textArea.append(" "); textArea.setCaretPosition(last + 1); } textArea.setCaretPosition(textArea.getText().length()); } } });