• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:JTextAreaの最終行だけ編集可能になるよう設定する
#navi(../)
#tags(DocumentFilter, Element, JTextArea, JTextComponent)
RIGHT:Posted by &author(aterai); at 2012-12-24
*JTextAreaの最終行だけ編集可能になるよう設定する [#zaa011b0]
``DocumentFilter``を使用して最終行のみ編集可能な``JTextArea``を作成します。

-&jnlp;
-&jar;
-&zip;

//#screenshot
#ref(https://lh3.googleusercontent.com/-WoZIsdy2Qd0/UNcd6P73NAI/AAAAAAAABZg/a2O8KLk4hVQ/s800/LastLineEditableTextArea.png)

**サンプルコード [#k6b28166]
#code(link){{
class NonEditableLineDocumentFilter extends DocumentFilter {
  public static final String PROMPT = "> ";
  @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")) {
        String line = doc.getText(promptPosition, offset-promptPosition);
        String[] args = line.split(" ");
        String cmd = args[0];
        if(cmd.isEmpty()) {
          text = "";
        }else{
          text = String.format("\n%s: command not found", cmd);
        }
        text += "\n"+PROMPT;
      }
      fb.replace(offset, length, text, attrs);
    }
  }
}
}}

**解説 [#c57d84df]
- ``DocumentFilter#replace(...)``をオーバーライド
- ``Document#getDefaultRootElement()``でルートエレメントを取得し、``Element#getElementCount()``で全体の行数を取得
- ``offset``(文字挿入位置)から``Element#getElementIndex(offset)``で、挿入位置の行番号と、``Element``を取得
- 上記の「挿入位置の行番号」と「全体の行数-1」が等しい場合だけ、``DocumentFilter.FilterBypass#replace(...)``を実行(編集可能)する
-- 上記のサンプルでは、コマンドプロンプト風に、最終行の行頭にあるプロンプトは編集不可で、改行の入力ごとに最終行の文字列を評価してメッセージを追加表示している

**参考リンク [#hf263a31]
- [[JTextAreaの一部を編集不可にする>Swing/NonEditableLine]]

**コメント [#re29de04]
#comment