[英]Make parts of a JTextArea non editable (not the whole JTextArea!)
I'm currently working on a console window in Swing. It's based on a JTextArea and works like a common command line.我目前正在 Swing 中的控制台 window 上工作。它基于 JTextArea 并且像普通命令行一样工作。 You type a command in one line and press enter.您在一行中键入一条命令,然后按回车键。 In the next line, the output is shown and under that output, you could write the next command.在下一行中,显示了 output,在该 output 下,您可以编写下一条命令。
Now I want, that you could only edit the current line with your command.现在我想要的是,您只能使用您的命令编辑当前行。 All lines above (old commands and results) should be non editable.上面的所有行(旧命令和结果)都应该是不可编辑的。 How can I do this?我怎样才能做到这一点?
You do not need to create your own component.您不需要创建自己的组件。
This can be done (as in I have done it) using a custom DocumentFilter .这可以使用自定义DocumentFilter来完成(就像我已经完成的那样)。
You can get the document from textPane.getDocument()
and set a filter on it by document.setFilter()
.您可以从textPane.getDocument()
获取文档并通过document.setFilter()
对其设置过滤器。 Within the filter, you can check the prompt position, and only allow modifications if the position is after the prompt.在过滤器中,您可以检查提示 position,并且仅当 position 在提示之后时才允许修改。
For example:例如:
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);
}
}
}
However, this prevents you from programmatically inserting content into the output (noneditable) section of the terminal.但是,这会阻止您以编程方式将内容插入终端的 output(不可编辑)部分。 What you can do instead is either a passthrough flag on your filter that you set when you're about to add the output, or (what I did) set the document filter to null before appending the output, and then reset it when you're done.您可以做的是在您要添加 output 时设置过滤器上的直通标志,或者(我所做的)在附加 output 之前将文档过滤器设置为 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, you need to implement your own control AFAIK,您需要实施自己的控制
Maybe you could simulate it with a list of textfields(even enabled and odd disabled) or a mix of textfields/labels也许您可以使用文本字段列表(偶数启用和奇数禁用)或文本字段/标签的混合来模拟它
EDIT:编辑:
I would bet for a non-editable textarea and an editable textfield.我敢打赌不可编辑的文本区域和可编辑的文本字段。 Type in textfield, press enter, add "command" and output to the textarea在文本字段中输入,按回车,将“命令”和 output 添加到文本区域
This is my implemitation of a document filter acting as a console in java. However with some modifications to allow me to have a " command area" and a "log area", meaning the results from commands print in the log area and the actual command prints in the command area.这是我在 java 中充当控制台的文档过滤器的实现。但是,通过一些修改,我可以拥有一个“命令区域”和一个“日志区域”,这意味着在日志区域和实际命令中打印命令的结果在命令区域打印。 The log area is just another Jtext area that is nonEditable.日志区域只是另一个不可编辑的 Jtext 区域。 I found thisthread to be helpful, so mabey someone trying to achive something similar to this implementation can find some pointers!我发现这个线程很有帮助,所以也许有人试图实现类似于这个实现的东西可以找到一些指针!
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);
}
}
}
What about that, when ">> " is the beginning of every line in the command line where the user can input a command:那么,当“>>”是命令行中用户可以输入命令的每一行的开头时:
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());
}
}
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.