UndoManagerを使用した文字列選択ペーストの動作を変更する
Total: 5240, Today: 2, Yesterday: 0
Posted by aterai at 
Last-modified: 
Summary
JTextFieldなどにUndoManagerを設定し、文字列を選択してペーストした後のUndoの動作を変更します。
Screenshot

Advertisement
Source Code Examples
class CustomUndoPlainDocument extends PlainDocument {
  private CompoundEdit compoundEdit;
  @Override protected void fireUndoableEditUpdate(UndoableEditEvent e) {
    if (compoundEdit == null) {
      super.fireUndoableEditUpdate(e);
    } else {
      compoundEdit.addEdit(e.getEdit());
    }
  }
  @Override public void replace(
      int offset, int length, String text, AttributeSet attrs)
      throws BadLocationException {
    if (length == 0) { // insert
      System.out.println("insert");
      super.replace(offset, length, text, attrs);
    } else { // replace
      System.out.println("replace");
      compoundEdit = new CompoundEdit();
      super.fireUndoableEditUpdate(new UndoableEditEvent(this, compoundEdit));
      super.replace(offset, length, text, attrs);
      compoundEdit.end();
      compoundEdit = null;
    }
  }
}
Description
- 上: Default- JTextComponent#setText(String)メソッドや文字列を選択してペーストした場合、- Document#replace(...)で実行される- Document#remove(...)と- Document#insertString(...)が別々に- UndoManagerに登録される仕様なので- 2回- Undoしないとペースト前の状態まで戻らない
 
- 中: Document#replace()+AbstractDocument#fireUndoableEditUpdate()- Document#replace(...)をオーバーライドし、- 直接- UndoManager#undoableEditHappened(...)を使って取り消し可能な編集を登録- setText(...)での文字列の削除と追加を- CompoundEditにまとめる
- 実際の置換は- removeUndoableEditListener(...)で- UndoManagerを一時的に削除した後に行う(直後に- addUndoableEditListener()で再登録)
- 登録する- UndoableEditでの- Undo、- Redo時の置換も- UndoManagerを一時的に削除して行う
- メモ: このサンプルでは選択状態を復元していない
 
- 下: DocumentFilter#replace()+UndoableEditListener#undoableEditHappened()- DocumentFilter#replace(...)をオーバーライドし、文字列の置換で発生する削除と追加の- UndoableEditを別途用意した- CompoundEditにまとめてから- UndoManager#addEdit(...)で追加- class DocumentFilterUndoManager extends UndoManager { private CompoundEdit compoundEdit; private final transient DocumentFilter undoFilter = new DocumentFilter() { @Override public void replace( DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { if (length == 0) { fb.insertString(offset, text, attrs); } else { compoundEdit = new CompoundEdit(); fb.replace(offset, length, text, attrs); compoundEdit.end(); addEdit(compoundEdit); compoundEdit = null; } } }; public DocumentFilter getDocumentFilter() { return undoFilter; } @Override public void undoableEditHappened(UndoableEditEvent e) { Optional.ofNullable(compoundEdit).orElse(this).addEdit(e.getEdit()); } }
 
Reference
- Undo two or more actions at once | Oracle Community
- Undo manager : Undo Redo « Swing JFC « Java
- Compound Undo Manager ≪ Java Tips Weblog
- Merging UndoableEdits in one to be undone all together in JEditorPane.
- java - JTextArea setText() & UndoManager - Stack Overflow
- java - Undo in JTextField and setText - Stack Overflow
- Java Swing「UndoManager」メモ(Hishidama's Swing-UndoManager Memo)
- Java Swingで複数のJTextFieldに対してUndo、Redoを行う(その2)-解決編 kyoはパソコンMaster or Slave?/ウェブリブログ
- バカが征く on Rails 2010年03月16日()
- UndoManagerでJTextFieldのUndo、Redoを行う