Thinker

            - long way to go...

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            24 隨筆 :: 0 文章 :: 143 評論 :: 0 Trackbacks
              StyledText是SWT包中的一個基礎(chǔ)組件,就像它的名字定義的那樣,通過它可以顯示各式各樣的字體。但是StyledText沒有提供Undo/Redo的功能,很是讓人不爽,下面給一個簡單的例子,演示在StyledText增加Undo/Redo操作,同時在這個自定義的StyledText中增加了刪除選中文本、清除全部文本的動作支持。
              思路很簡單,就是監(jiān)聽文本內(nèi)容更改事件,然后根據(jù)更改的內(nèi)容生成Undo操作存入Undo操作棧中,在Undo操作棧中維護(hù)了兩個列表UndoList和RedoList,當(dāng)發(fā)出Undo操作命令的時候,從Undo操作列表中取出一個Undo操作,執(zhí)行其undo()方法,然后將其放入Redo操作列表中。如果發(fā)出Redo操作命令,就從Redo操作列表中出一個Redo操作,執(zhí)行其redo()方法,然后將其放入Undo操作列表中。
              本篇文章只是給出了一個簡單的演示示例,需要改進(jìn)的地方是監(jiān)聽文本更改時,應(yīng)該采用一定的規(guī)則策略來生成Undo操作,否則每輸入或者刪除一個字符都會創(chuàng)建一個Undo操作,這樣就會產(chǎn)生非常多的Undo操作,并且也不符合日常使用習(xí)慣。日后有時間的話我會整理一下改進(jìn)的版本發(fā)布出來。如果你有興趣也可以研究一下。
              另外由于StyledText的invokeAction()方法中Action的動作不夠充足,致使無法用setKeyBinding()方法方便的將快捷鍵與執(zhí)行動作綁定,通過重寫StyledText中的invokeAction()方法可以定制某些自己的動作,完善StyledText的功能。

          下面是Undo操作管理器UndoManager的代碼:
            1 import org.eclipse.core.commands.ExecutionException;
            2 import org.eclipse.core.commands.operations.AbstractOperation;
            3 import org.eclipse.core.commands.operations.IOperationHistory;
            4 import org.eclipse.core.commands.operations.IUndoContext;
            5 import org.eclipse.core.commands.operations.ObjectUndoContext;
            6 import org.eclipse.core.commands.operations.OperationHistoryFactory;
            7 import org.eclipse.core.runtime.IAdaptable;
            8 import org.eclipse.core.runtime.IProgressMonitor;
            9 import org.eclipse.core.runtime.IStatus;
           10 import org.eclipse.core.runtime.Status;
           11 import org.eclipse.swt.custom.ExtendedModifyEvent;
           12 import org.eclipse.swt.custom.ExtendedModifyListener;
           13 import org.eclipse.swt.custom.StyledText;
           14 
           15 /**
           16  * 管理Undo操作,用于監(jiān)聽文本域的文本改變事件,生成Undo操作并記錄。<br>
           17  * 
           18  * @author qujinlong
           19  */
           20 public class UndoManager
           21 {
           22   /*
           23    * 用于存儲歷史Undo操作,每改變一次文本內(nèi)容,就將構(gòu)造一個Undo操作存入OperationHistory中。
           24    */
           25   private final IOperationHistory opHistory;
           26 
           27   /*
           28    * Undo操作上下文,一般用于在OperationHistory中查找當(dāng)前文本框的Undo操作。
           29    */
           30   private IUndoContext undoContext = null;
           31 
           32   /*
           33    * 所要監(jiān)聽的需要實現(xiàn)Undo操作的文本框。
           34    */
           35   private StyledText styledText = null;
           36 
           37   private int undoLevel = 0;
           38 
           39   public UndoManager(int undoLevel)
           40   {
           41     opHistory = OperationHistoryFactory.getOperationHistory();
           42 
           43     setMaxUndoLevel(undoLevel);
           44   }
           45 
           46   public void setMaxUndoLevel(int undoLevel)
           47   {
           48     this.undoLevel = Math.max(0, undoLevel);
           49 
           50     if (isConnected())
           51       opHistory.setLimit(undoContext, this.undoLevel);
           52   }
           53 
           54   public boolean isConnected()
           55   {
           56     return styledText != null;
           57   }
           58 
           59   /*
           60    * 將Undo管理器與指定的StyledText文本框相關(guān)聯(lián)。
           61    */
           62   public void connect(StyledText styledText)
           63   {
           64     if (! isConnected() && styledText != null)
           65     {
           66       this.styledText = styledText;
           67 
           68       if (undoContext == null)
           69         undoContext = new ObjectUndoContext(this);
           70 
           71       opHistory.setLimit(undoContext, undoLevel);
           72       opHistory.dispose(undoContext, truetruefalse);
           73 
           74       addListeners();
           75     }
           76   }
           77 
           78   public void disconnect()
           79   {
           80     if (isConnected())
           81     {
           82       removeListeners();
           83 
           84       styledText = null;
           85 
           86       opHistory.dispose(undoContext, truetruetrue);
           87 
           88       undoContext = null;
           89     }
           90   }
           91 
           92   private ExtendedModifyListener extendedModifyListener = null;
           93 
           94   private boolean isUndoing = false;
           95 
           96   /*
           97    * 向Styled中注冊監(jiān)聽文本改變的監(jiān)聽器。
           98    * 
           99    * 如果文本改變,就構(gòu)造一個Undo操作壓入Undo操作棧中。
          100    */
          101   private void addListeners()
          102   {
          103     if (styledText != null)
          104     {
          105       extendedModifyListener = new ExtendedModifyListener() {
          106         public void modifyText(ExtendedModifyEvent event)
          107         {
          108           if (isUndoing)
          109             return;
          110 
          111           String newText = styledText.getText().substring(event.start,
          112               event.start + event.length);
          113 
          114           UndoableOperation operation = new UndoableOperation(undoContext);
          115 
          116           operation.set(event.start, newText, event.replacedText);
          117 
          118           opHistory.add(operation);
          119         }
          120       };
          121 
          122       styledText.addExtendedModifyListener(extendedModifyListener);
          123     }
          124   }
          125 
          126   private void removeListeners()
          127   {
          128     if (styledText != null)
          129     {
          130       if (extendedModifyListener != null)
          131       {
          132         styledText.removeExtendedModifyListener(extendedModifyListener);
          133 
          134         extendedModifyListener = null;
          135       }
          136     }
          137   }
          138 
          139   public void redo()
          140   {
          141     if (isConnected())
          142     {
          143       try
          144       {
          145         opHistory.redo(undoContext, nullnull);
          146       }
          147       catch (ExecutionException ex)
          148       {
          149       }
          150     }
          151   }
          152 
          153   public void undo()
          154   {
          155     if (isConnected())
          156     {
          157       try
          158       {
          159         opHistory.undo(undoContext, nullnull);
          160       }
          161       catch (ExecutionException ex)
          162       {
          163       }
          164     }
          165   }
          166 
          167   /*
          168    * Undo操作用于記錄StyledText的文本被改變時的相關(guān)數(shù)據(jù)。
          169    * 
          170    * 比如文本框中本來的文本為111222333,如果此時選中222替換為444(用復(fù)制粘帖的方法),
          171    * 
          172    * 則Undo操作中記錄的相關(guān)數(shù)據(jù)為: startIndex = 3; newText = 444; replacedText = 222;
          173    */
          174   private class UndoableOperation extends AbstractOperation
          175   {
          176     // 記錄Undo操作時,被替換文本的開始索引
          177     protected int startIndex = - 1;
          178 
          179     // 新輸入的文本
          180     protected String newText = null;
          181 
          182     // 被替換掉的文本
          183     protected String replacedText = null;
          184 
          185     public UndoableOperation(IUndoContext context)
          186     {
          187       super("Undo-Redo");
          188 
          189       addContext(context);
          190     }
          191 
          192     /*
          193      * 設(shè)置Undo操作中要存儲的相關(guān)數(shù)據(jù)。
          194      */
          195     public void set(int startIndex, String newText, String replacedText)
          196     {
          197       this.startIndex = startIndex;
          198 
          199       this.newText = newText;
          200       this.replacedText = replacedText;
          201     }
          202 
          203     /*
          204      * (non-Javadoc)
          205      * 
          206      * @see org.eclipse.core.commands.operations.AbstractOperation#undo(org.eclipse.core.runtime.IProgressMonitor,
          207      *      org.eclipse.core.runtime.IAdaptable)
          208      */
          209     public IStatus undo(IProgressMonitor monitor, IAdaptable info)
          210         throws ExecutionException
          211     {
          212       isUndoing = true;
          213       styledText.replaceTextRange(startIndex, newText.length(), replacedText);
          214       isUndoing = false;
          215 
          216       return Status.OK_STATUS;
          217     }
          218 
          219     /*
          220      * (non-Javadoc)
          221      * 
          222      * @see org.eclipse.core.commands.operations.AbstractOperation#redo(org.eclipse.core.runtime.IProgressMonitor,
          223      *      org.eclipse.core.runtime.IAdaptable)
          224      */
          225     public IStatus redo(IProgressMonitor monitor, IAdaptable info)
          226         throws ExecutionException
          227     {
          228       isUndoing = true;
          229       styledText.replaceTextRange(startIndex, replacedText.length(), newText);
          230       isUndoing = false;
          231 
          232       return Status.OK_STATUS;
          233     }
          234 
          235     /*
          236      * (non-Javadoc)
          237      * 
          238      * @see org.eclipse.core.commands.operations.AbstractOperation#execute(org.eclipse.core.runtime.IProgressMonitor,
          239      *      org.eclipse.core.runtime.IAdaptable)
          240      */
          241     public IStatus execute(IProgressMonitor monitor, IAdaptable info)
          242         throws ExecutionException
          243     {
          244       return Status.OK_STATUS;
          245     }
          246   }
          247 }


          下面是擴(kuò)展的StyledText類:
            1 import org.eclipse.swt.SWT;
            2 import org.eclipse.swt.custom.ST;
            3 import org.eclipse.swt.custom.StyledText;
            4 import org.eclipse.swt.layout.GridData;
            5 import org.eclipse.swt.layout.GridLayout;
            6 import org.eclipse.swt.widgets.Composite;
            7 import org.eclipse.swt.widgets.Display;
            8 import org.eclipse.swt.widgets.Shell;
            9 
           10 /**
           11  * 自定義的StyledText,增加了Undo、Redo和清除操作。<br>
           12  * 
           13  * @author qujinlong
           14  */
           15 public class MyStyledText extends StyledText
           16 {
           17   /**
           18    * @param parent
           19    * @param style
           20    */
           21   public MyStyledText(Composite parent, int style)
           22   {
           23     super(parent, style);
           24   }
           25 
           26   /*
           27    * (non-Javadoc)
           28    * 
           29    * @see org.eclipse.swt.custom.StyledText#invokeAction(int)
           30    */
           31   public void invokeAction(int action)
           32   {
           33     // 增加一個自定義的刪除操作,只有當(dāng)選中文本的時候才將文本刪除。
           34     // 否則,ST.DELETE_NEXT會將光標(biāo)所在位置的后一個字符刪除。
           35     if (action == ActionCode.DELETE && getSelectionCount() > 0)
           36       action = ST.DELETE_NEXT;
           37 
           38     super.invokeAction(action);
           39 
           40     switch (action)
           41     {
           42       case ActionCode.UNDO:
           43         undo();
           44         break;
           45       case ActionCode.REDO:
           46         redo();
           47         break;
           48       case ActionCode.CLEAR:
           49         clear();
           50         break;
           51     }
           52   }
           53 
           54   private void undo()
           55   {
           56     if (undoManager != null)
           57       undoManager.undo();
           58   }
           59 
           60   private void redo()
           61   {
           62     if (undoManager != null)
           63       undoManager.redo();
           64   }
           65 
           66   private void clear()
           67   {
           68     super.setText("");
           69   }
           70 
           71   private UndoManager undoManager = null;
           72 
           73   /**
           74    * @return Returns undoManager.
           75    */
           76   public UndoManager getUndoManager()
           77   {
           78     return undoManager;
           79   }
           80 
           81   /**
           82    * @param undoManager - The undoManager to set.
           83    */
           84   public void setUndoManager(UndoManager undoManager)
           85   {
           86     this.undoManager = undoManager;
           87   }
           88 
           89   /*
           90    * (non-Javadoc)
           91    * 
           92    * @see org.eclipse.swt.widgets.Widget#dispose()
           93    */
           94   public void dispose()
           95   {
           96     if (undoManager != null)
           97       undoManager.disconnect();
           98 
           99     super.dispose();
          100   }
          101 
          102   public static class ActionCode
          103   {
          104     public static final int UNDO = Integer.MAX_VALUE;
          105 
          106     public static final int REDO = UNDO - 1;
          107 
          108     public static final int CLEAR = UNDO - 2;
          109 
          110     public static final int DELETE = UNDO - 3;
          111   }
          112 
          113   public static void main(String[] args)
          114   {
          115     final Display display = Display.getDefault();
          116     final Shell shell = new Shell();
          117     shell.setLayout(new GridLayout());
          118     shell.setSize(420250);
          119     shell.setText("SWT Application");
          120 
          121     MyStyledText styledText = new MyStyledText(shell, SWT.BORDER);
          122     GridData gd_styledText = new GridData(SWT.FILL, SWT.CENTER, falsefalse);
          123     gd_styledText.heightHint = 200;
          124     gd_styledText.widthHint = 400;
          125     styledText.setLayoutData(gd_styledText);
          126 
          127     // Ctrl+C, Ctrl+X, Ctrl+V 都是StyledText的默認(rèn)行為。
          128 
          129     // styledText.setKeyBinding('C' | SWT.CTRL, ST.COPY);
          130     // styledText.setKeyBinding('V' | SWT.CTRL, ST.PASTE);
          131     // styledText.setKeyBinding('X' | SWT.CTRL, ST.CUT);
          132 
          133     styledText.setKeyBinding('A' | SWT.CTRL, ST.SELECT_ALL);
          134 
          135     styledText.setKeyBinding('Z' | SWT.CTRL, ActionCode.UNDO);
          136     styledText.setKeyBinding('Y' | SWT.CTRL, ActionCode.REDO);
          137     styledText.setKeyBinding('F' | SWT.CTRL, ActionCode.CLEAR);
          138     styledText.setKeyBinding('D' | SWT.CTRL, ActionCode.DELETE);
          139 
          140     UndoManager undoManager = new UndoManager(50);
          141     undoManager.connect(styledText);
          142 
          143     styledText.setUndoManager(undoManager);
          144 
          145     shell.open();
          146 
          147     shell.layout();
          148 
          149     while (! shell.isDisposed())
          150     {
          151       if (! display.readAndDispatch())
          152         display.sleep();
          153     }
          154   }
          155 }
              本示例著重演示如何實現(xiàn)Undo/Redo操作,也可以參見JFace的TextViewer的Undo/Redo操作的實現(xiàn)。
          posted on 2007-06-07 10:25 Long 閱讀(4980) 評論(7)  編輯  收藏 所屬分類: Java

          評論

          # re: 為SWT的StyledText添加Undo、Redo操作 2007-06-07 10:39 Long
          如果想寫純SWT應(yīng)用程序,可以自己實現(xiàn)一個OperationHistory,實際上就是維護(hù)Undo/Redo兩個操作列表/棧。  回復(fù)  更多評論
            

          # re: 為SWT的StyledText添加Undo、Redo操作 2007-06-07 12:17 BeanSoft
          貌似可以這里直接用 Swing 的 UNDO/REDO 機(jī)制.  回復(fù)  更多評論
            

          # re: 為SWT的StyledText添加Undo/Redo操作以及對快捷鍵動作綁定的支持 2007-06-11 12:00 Long
          上次看到網(wǎng)友說貼代碼時不要顯示列號。
          呵呵,顯示列號沒關(guān)系,只要用UltraEdit的列模式很容易就刪除掉了。  回復(fù)  更多評論
            

          # re: 為SWT的StyledText添加Undo/Redo操作以及對快捷鍵動作綁定的支持 2007-09-07 09:40 wang
          請教下,對小鍵盤回車 綁定快捷鍵 ,怎樣寫代碼呢,忘告知,謝謝  回復(fù)  更多評論
            

          # 為SWT的StyledText添加Undo/Redo操作以及對快捷鍵動作綁定的支持 2008-07-15 11:38 zheng1285
          如果還要實現(xiàn) 從網(wǎng)頁上復(fù)制過來的粘貼到StyledText中能不能帶它的屬性呢?
          比如它有鏈接、加粗等等。  回復(fù)  更多評論
            

          # 為SWT的StyledText添加Undo/Redo操作以及對快捷鍵動作綁定的支持 2008-07-15 11:39 zheng1285
          <B>如果還要實現(xiàn) 從網(wǎng)頁上復(fù)制過來的粘貼到StyledText中能不能帶它的屬性呢?
          比如它有鏈接、加粗等等。<B>  回復(fù)  更多評論
            

          # re: 為SWT的StyledText添加Undo/Redo操作以及對快捷鍵動作綁定的支持[未登錄] 2014-09-11 14:10 1
          jianren  回復(fù)  更多評論
            

          主站蜘蛛池模板: 邮箱| 育儿| 新密市| 湟源县| 沁水县| 来宾市| 朝阳市| 吴川市| 黎城县| 临颍县| 永年县| 灵川县| 太仆寺旗| 平阴县| 綦江县| 琼海市| 宜兰县| 民乐县| 米林县| 吉首市| 昌邑市| 巴林左旗| 诸城市| 板桥市| 通山县| 禹城市| 乌兰察布市| 额济纳旗| 台江县| 沂水县| 嘉峪关市| 凤山县| 西和县| 射阳县| 开远市| 清水河县| 阜南县| 安岳县| 台南市| 怀来县| 都昌县|