2012-10-11 37 views
2

JTextField具有撤消支持功能。它適用於用戶interacion,但不幸的是,如果方法setText(String str)被調用,結果兩個撤消編輯,而不是一個。因此,這段代碼的外觀和感覺很好,但不工作:在JTextField和setText中撤消

UndoManager undoManager = new UndoManager(); 
JTextField tf = new JTextField(); 
tf.setText("initial value"); 
tf.getDocument().addUndoableEditListener(undoManager); 
tf.setText("new value"); 
undoManager.undo(); 
System.out.println(tf.getText()); // Prints empty string 
undoManager.undo(); 
System.out.println(tf.getText()); // Prints "initial value" as expected 

能的JTextField以某種方式處理的setText()因爲只有一個UndoableEdit中的?的DragAndDropUndoAndRedo

+0

以編程方式設置文本似乎是調用['discardAllEdits()'](http://docs.oracle.com/javase/7/docs/api/javax/swing/undo/UndoManager.html#discardAllEdits% 28%29)。 –

+0

@Andrew Thompson不,實際上我有一個彈出式菜單,包含一些文本操作,比如大寫字母,反轉字符串等。我希望這些操作可以在一個動作中撤消,否則用戶只需單擊一次即可大寫一個字符串。需要進行兩次撤消才能刪除。 – AvrDragon

回答

1

另一種選擇是重寫文件#替換(。 ..)

import java.awt.*; 
import java.awt.event.*; 
import java.util.Date; 
import javax.swing.*; 
import javax.swing.text.*; 
import javax.swing.undo.*; 
import javax.swing.event.*; 

public class ReplaceUndoableEditDemo { 
    private final UndoManager um = new UndoManager(); 
    private final JTextField tf = new JTextField(24); 
    private final UndoManager undoManager = new UndoManager(); 
    private final JTextField field = new JTextField(24); 
    private final Document doc = new PlainDocument() { 
    @Override public void replace(
     int offset, int length, String text, AttributeSet attrs) 
    throws BadLocationException { 
     undoManager.undoableEditHappened(new UndoableEditEvent(
      this, new ReplaceUndoableEdit(offset, length, text))); 
     replaceIgnoringUndo(offset, length, text, attrs); 
    } 
    private void replaceIgnoringUndo(
     int offset, int length, String text, AttributeSet attrs) 
    throws BadLocationException { 
     for(UndoableEditListener uel: getUndoableEditListeners()) { 
     removeUndoableEditListener(uel); 
     } 
     super.replace(offset, length, text, attrs); 
     for(UndoableEditListener uel: getUndoableEditListeners()) { 
     addUndoableEditListener(uel); 
     } 
    } 
    class ReplaceUndoableEdit extends AbstractUndoableEdit { 
     private final String oldValue; 
     private final String newValue; 
     private int offset; 
     public ReplaceUndoableEdit(int offset, int length, String newValue) { 
     String txt; 
     try { 
      txt = getText(offset, length); 
     } catch(BadLocationException e) { 
      txt = null; 
     } 
     this.oldValue = txt; 
     this.newValue = newValue; 
     this.offset = offset; 
     } 
     @Override public void undo() throws CannotUndoException { 
     try { 
      replaceIgnoringUndo(offset, newValue.length(), oldValue, null); 
     } catch(BadLocationException ex) { 
      throw new CannotUndoException(); 
     } 
     } 
     @Override public void redo() throws CannotRedoException { 
     try { 
      replaceIgnoringUndo(offset, oldValue.length(), newValue, null); 
     } catch(BadLocationException ex) { 
      throw new CannotUndoException(); 
     } 
     } 
     @Override public boolean canUndo() { 
     return true; 
     } 
     @Override public boolean canRedo() { 
     return true; 
     } 
    } 
    }; 
    public JComponent makeUI() { 
    tf.getDocument().addUndoableEditListener(um); 
    doc.addUndoableEditListener(undoManager); 
    field.setDocument(doc); 
    field.setText("aaaaaaaaa"); 
    tf.setText("default"); 
    JPanel p = new JPanel(); 
    p.add(tf); 
    p.add(field); 
    p.add(new JButton(new AbstractAction("undo") { 
     @Override public void actionPerformed(ActionEvent e) { 
     try { 
      undoManager.undo(); 
      um.undo(); 
     } catch(Exception ex) { 
      java.awt.Toolkit.getDefaultToolkit().beep(); 
     } 
     } 
    })); 
    p.add(new JButton(new AbstractAction("redo") { 
     @Override public void actionPerformed(ActionEvent e) { 
     try { 
      undoManager.redo(); 
      um.redo(); 
     } catch(Exception ex) { 
      java.awt.Toolkit.getDefaultToolkit().beep(); 
     } 
     } 
    })); 
    p.add(new JButton(new AbstractAction("setText") { 
     @Override public void actionPerformed(ActionEvent e) { 
     String str = new Date().toString(); 
     tf.setText(str); 
     field.setText(str); 
     } 
    })); 
    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 ReplaceUndoableEditDemo().makeUI()); 
    f.setSize(320, 240); 
    f.setLocationRelativeTo(null); 
    f.setVisible(true); 
    } 
} 
1

不迷有將數據加載到UndoManager並定義UndoAction undoAction = new UndoAction();相同是可能的簡單Graphics或E.I.

class UndoHandler implements UndoableEditListener { 

     @Override 
     public void undoableEditHappened(UndoableEditEvent e) { 
      undoManager.addEdit(e.getEdit()); 
      undoAction.update(); 
     } 
    } 

,並創建Swing Action(添加到JButton)沖洗含量研究回JTextField

class UndoAction extends AbstractAction { 

     private static final long serialVersionUID = 1L; 

     UndoAction() { 
      super("Undo"); 
      setEnabled(false); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      try { 
       undo.undo(); 
      } catch (CannotUndoException ex) { 
       System.out.println("Unable to undo: " + ex); 
       ex.printStackTrace(); 
      } 
      update(); 
     } 

     protected void update() { 
      if (undo.canUndo()) { 
       setEnabled(true); 
       putValue(Action.NAME, undo.getUndoPresentationName()); 
      } else { 
       setEnabled(false); 
       putValue(Action.NAME, "Undo"); 
      } 
     } 
    } 
+0

沒有真正瞭解你的代碼,但是你的意思是擴展UndoableEdit並在重載的undo/redo方法中設置setText? – AvrDragon

1

找到一個解決辦法:

public class SetTextEditUndo extends AbstractUndoableEdit { 

    public JTextField src; 
    public String oldValue; 
    public String newValue; 

    public SetTextEditUndo(JTextField src, String oldValue, String newValue) { 
     this.src = src; 
     this.oldValue = oldValue; 
     this.newValue = newValue; 
    } 

    @Override 
    public void undo() throws CannotUndoException { 
     setTextIgnoringUndo(src, oldValue); 
    } 

    @Override 
    public void redo() throws CannotRedoException { 
     setTextIgnoringUndo(src, newValue); 
    } 

    @Override 
    public boolean canUndo() { 
     return true; 
    } 

    @Override 
    public boolean canRedo() { 
     return true; 
    } 

    public static void setTextIgnoringUndo(JTextField tf, String str) { 
     PlainDocument doc = (PlainDocument) tf.getDocument(); 
     UndoableEditListener uel = doc.getUndoableEditListeners()[0]; 
     doc.removeUndoableEditListener(uel); 
     tf.setText(str); 
     doc.addUndoableEditListener(uel); 
    } 

}