简体   繁体   English

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM