2009-01-06 63 views
4

我正在嘗試編寫一種支持某種着色的JTextPane:當用戶輸入文本時,我正在運行一些根據特定算法對文本進行着色的代碼。這很好。從Swing的撤消管理器中隱藏某些動作

問題是着色操作是使用撤銷管理器(具有EventType.CHANGE的DefaultDocumentEvent)進行註冊的。所以當用戶點擊撤消時,顏色消失。只有在第二次撤消請求時,文本本身才會回滾。

(請注意,着色算法有點慢,所以我不能在插入文本時對其着色)。

如果我試圖阻止CHANGE事件到達撤消管理器,那麼在多次撤消請求後我會得到一個異常:這是因爲文檔內容不符合可撤銷編輯對象的期望。

任何想法?

回答

1

你可以攔截CHANGE編輯和包裝每一個在另一個UndoableEdit中,其isSignificant()方法返回false,將它添加到的UndoManager之前。然後,每個撤銷命令將撤消最近的INSERT或REMOVE編輯,以及自此之後發生的每個CHANGE編輯。

最終,我想你會發現JTextPane/StyledDocument/etc提供的樣式機制。對於這種事情太有限了。它速度很慢,它使用的內存太多,它基於用於跟蹤文檔詞法結構的元素樹。對於用戶使用樣式的應用程序(比如文字處理器),沒關係(我猜),但不適用於必須隨用戶輸入不斷更新樣式的語法高亮條。

基於Swing JTextComponent,ViewDocument類的自定義實現的語法高亮編輯器有幾個例子。有些人,比如JEdit,幾乎重新實現了整個javax.swing.text包,但我認爲你不需要那麼遠。

1

你如何防止CHANGE事件到達撤銷管理器?

在CHANGE排隊之後,您能否立即發送lastEdit()。die()調用的UndoManager?

1

我只能假設你如何做文字着色。如果您正在StyledDocuments中更改字符屬性方法,您可以獲取撤銷偵聽器,並暫時從該操作的文檔中註銷它,然後一旦顏色更改已完成,則可以重新註冊偵聽器。

對於您在那裏嘗試做的事情應該沒問題。

希望幫助

+0

不要這樣做!我得到了一個非常糟糕的java內部異常,試圖這樣做。完整的Swing線程在我身上墜毀,每次重繪都拋出此異常:線程「AWT-EventQueue-0」中的異常java.lang.IllegalArgumentException:在sun.util.locale.provider.RuleBasedBreakIterator.checkOffset(RuleBasedBreakIterator。java:759)... – Adrodoc55 2015-12-28 22:30:11

0

我剛剛經歷了這個問題。這裏是我的解決方案:

private class UndoManagerFix extends UndoManager { 

    private static final long serialVersionUID = 5335352180435980549L; 

    @Override 
    public synchronized void undo() throws CannotUndoException { 
     do { 
      UndoableEdit edit = editToBeUndone(); 
      if (edit instanceof AbstractDocument.DefaultDocumentEvent) { 
       AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) edit; 
       if (event.getType() == EventType.CHANGE) { 
        super.undo(); 
        continue; 
       } 
      } 
      break; 
     } while (true); 

     super.undo(); 
    } 

    @Override 
    public synchronized void redo() throws CannotRedoException { 
     super.redo(); 
     int caretPosition = getCaretPosition(); 

     do { 
      UndoableEdit edit = editToBeRedone(); 
      if (edit instanceof AbstractDocument.DefaultDocumentEvent) { 
       AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) edit; 
       if (event.getType() == EventType.CHANGE) { 
        super.redo(); 
        continue; 
       } 
      } 
      break; 
     } while (true); 

     setCaretPosition(caretPosition); 
    } 

} 

這是我的自定義的JTextPane一個內部類,這樣我就可以固定在重做的插入位置。