好好生活,努力工作,天天向上!

          BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
            46 Posts :: 1 Stories :: 178 Comments :: 0 Trackbacks

            是不是覺得Windows的倒計(jì)時(shí)關(guān)機(jī)對(duì)話框很酷?
                                 

             其實(shí)你也可以通過SWT的對(duì)話框來實(shí)現(xiàn)這個(gè)功能,如果你真的夠無聊的話,可以用來嚇唬一下你的用戶,當(dāng)然你的確定你的人緣很好才行.

             好了,開場白到此為止,下面進(jìn)入正題:

              我設(shè)計(jì)這個(gè)倒計(jì)時(shí)對(duì)話框主要是為了讓我們系統(tǒng)在自動(dòng)更新完成后自動(dòng)重啟,我們的系統(tǒng)提供了自動(dòng)更新的功能,而且有個(gè)數(shù)據(jù)傳輸模塊,數(shù)據(jù)傳輸模塊是使用Wrapper這個(gè)工具封裝Java程序成服務(wù),數(shù)據(jù)傳輸模塊會(huì)共享RCP客戶端的插件Jar包,由于Eclipse插件的特殊性,自動(dòng)更新完成后可能會(huì)在安裝目錄中存在同名稱但不同版本號(hào)的插件,具體細(xì)節(jié)省去7443個(gè)字節(jié)。

             想實(shí)現(xiàn)倒計(jì)時(shí)對(duì)話框,我們可以使用Timer這個(gè)定時(shí)工具類,這主要考慮到倒計(jì)時(shí)對(duì)話框要和RCP項(xiàng)目的主線程區(qū)分開來,對(duì)話框彈出不能夠影響用戶的操作,至少得讓他們的有時(shí)間保存信息不至于丟失,我們把這個(gè)類命名為 TimerMessageDialog .java, 根據(jù)MessageDialog中提供的方法,我們無法動(dòng)態(tài)顯示提示信息,比如還剩下多少時(shí)間.你可以重載MessageDialog的 createMessageArea(Composite composite) 方法,可以再TimerMessageDialog中新增一個(gè)字段引用 messageLabel ,比如 localMessageLabel ,然后對(duì) localMessageLabel 的值進(jìn)行修改,下面是我的實(shí)現(xiàn),可以參考一下:

           
          protected Control createMessageArea(Composite composite) {
              
          // create composite
              
          // create image
              Image image = getImage();
              
          if (image != null) {
                imageLabel 
          = new Label(composite, SWT.NULL);
                image.setBackground(imageLabel.getBackground());
                imageLabel.setImage(image);
          //      addAccessibleListeners(imageLabel, image);
                GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.BEGINNING)
                    .applyTo(imageLabel);
              }
              
          // create message
              if (message != null) {
                messageLabel 
          = new Label(composite, getMessageLabelStyle());
                TimerMessageDialog.localMessageLabel 
          = messageLabel;
                messageLabel.setText(message);
                GridDataFactory
                    .fillDefaults()
                    .align(SWT.FILL, SWT.BEGINNING)
                    .grab(
          truefalse)
                    .hint(
                        convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH),
                        SWT.DEFAULT).applyTo(messageLabel);
              }
              
          return composite;
            }

             然后我們添加一個(gè)打開對(duì)話框的方法:  open(final int second,final String message) ,second表示倒計(jì)時(shí)時(shí)間,message表示提示信息,在open方法中新建一個(gè) Timer 對(duì)象。對(duì)了,為了讓MessageDialog彈出后不阻塞線程的執(zhí)行,需要在調(diào)用對(duì)話框的open方法之前調(diào)用 setBlockOnOpen(false); 方法,下面是我的實(shí)現(xiàn),大家可以參考一下:

          /**
             * 打開定時(shí)關(guān)閉對(duì)話框,顧名思義,就是在指定的時(shí)間自動(dòng)關(guān)閉  。
             * 
          @author 劉堯興
             * 
          @param second
             * 
          @param message 
             
          */
            
          public void open(final int second,final String message) {
              setBlockOnOpen(
          false);
              open();
              
          //    final MessageFormat format = new MessageFormat("系統(tǒng)檢查到重要插件的更新,系統(tǒng)將會(huì)在 {0} 秒后自動(dòng)重啟,請(qǐng)注意保存文件");
              
              timer 
          = new Timer("檢查更新");
              
          final TimerTask task = new TimerTask() {
                
          int count = second;
                
          public void run() {
                  Display display 
          = Display.getDefault();
                  
          if (display == null) {
                    
          return;
                  }
                  display.asyncExec(
          new Runnable() {
                    
          public void run() {
                      
          try {

                        
          if (count == 0) {
                          cancel();
                          buttonPressed(Window.OK);
                        } 
          else {
                          count 
          -= 1;
                          
          if (!localMessageLabel.isDisposed()&&localMessageLabel != null) {
                            localMessageLabel.setText(message
          +"系統(tǒng)將在:" + count + "秒后自動(dòng)重啟");
          //                localMessageLabel.setText(format.format(new Object[]{new Integer(count)}));
                          }
                        }
                      
                      }
          catch (Exception e) {
                        e.printStackTrace();
                      }
                    }
                  });
                }
              };
              timer.schedule(task, 
          10001000);
            }

             這里的Timer是每一秒鐘執(zhí)行一次,在定時(shí)器執(zhí)行完成后應(yīng)該讓對(duì)話框自動(dòng)關(guān)閉,然后可以通知事件發(fā)起人來執(zhí)行對(duì)應(yīng)的操作,從這樣設(shè)計(jì)的角度上看,我們的需要在用戶點(diǎn)擊確認(rèn)或者取消或者關(guān)閉對(duì)話框時(shí)響應(yīng)用戶的操作,這樣我們的重載父類的 buttonPressed(int buttonId) 方法,在這個(gè)方法中執(zhí)行對(duì)應(yīng)的操作.比如這樣:

           
          protected void buttonPressed(int buttonId) {
              
          if(buttonId == Window.OK) {
                timer.cancel();
                firePropertyChange(IPropery.RESTART_OK_PRESSED, 
          falsetrue);
              } 
          else if(buttonId == Window.CANCEL) {
                close();
              }
            }

             這里我使用了java.util包中的 PropertyChangeListener 來監(jiān)聽屬性值的修改。這里的對(duì)話框應(yīng)該算是事件源,由這個(gè)發(fā)起屬性事件的修改通知,其他監(jiān)聽類根據(jù)接收到的信息作出相應(yīng)的響應(yīng)。我在TimerMessageDialog實(shí)現(xiàn)了一個(gè)內(nèi)部類: PropertyChangeSupportImpl ,這個(gè)類管理通知的對(duì)象: 
           

          /**
             * 屬性修改支持實(shí)現(xiàn)類  。 
             * 
          @author 劉堯興
             * <p>2009-8-18</p>
             
          */
            
          public class PropertyChangeSupportImpl {
              
              
          /** 屬性修改支持     */
              PropertyChangeSupport listeners 
          = new PropertyChangeSupport(this);

              
          /**
               * 添加屬性修改事件  。
               * 
          @author 劉堯興
               * 
          @param l
               
          */
              
          public void addPropertyChangeListener(PropertyChangeListener l) {
                listeners.addPropertyChangeListener(l);
              }

              
          /**
               * 通知修改事件發(fā)生  。
               * 
          @author 劉堯興
               * 
          @param prop
               * 
          @param old
               * 
          @param newValue
               
          */
              
          public void firePropertyChange(String prop, Object old, Object newValue) {
                listeners.firePropertyChange(prop, old, newValue);
              }

              
          /**
               * 通知事件修改  。
               * 
          @author 劉堯興
               * 
          @param prop
               * 
          @param child
               
          */
              
          protected void fireStructureChange(String prop, Object child) {
                listeners.firePropertyChange(prop, 
          null, child);
              }

              
          /**
               * 刪除屬性修改事件  。
               * 
          @author 劉堯興
               * 
          @param l
               
          */
              
          public void removePropertyChangeListener(PropertyChangeListener l) {
                listeners.removePropertyChangeListener(l);
              }
            }

             在完成這些之后,在監(jiān)聽類中注冊(cè)一個(gè)屬性修改的事件,比如在UpdatePlan這個(gè)類中執(zhí)行TimerMessageDialog的打開操作,那就的讓UpdatePlan這個(gè)類實(shí)現(xiàn) PropertyChangeListener 這個(gè)接口并實(shí)現(xiàn) propertyChange(final PropertyChangeEvent evt) 這個(gè)方法,這個(gè)方法可以根據(jù)傳過來的屬性名稱和屬性值執(zhí)行相應(yīng)的操作。UpdatePlan屬性注冊(cè)方式是:

          Display.getDefault().asyncExec(new Runnable() {
                @Override
                
          public void run() {
                  
          try {
                    TimerMessageDialog dialog 
          = new TimerMessageDialog(Display.getDefault().getActiveShell(),"系統(tǒng)信息","系統(tǒng)將要自動(dòng)重啟");
                    dialog.addPropertyChangeListener(
          this);
                    dialog.open(
          30,"");
                  }
                  
          catch (Exception e) {
                    e.printStackTrace();
                  }
                }
              });
            因?yàn)槲沂窃赗CP的非UI現(xiàn)在調(diào)用這個(gè)對(duì)話框,所以需要在Display的asyncExec方法啟用一個(gè)新的異步線程.這樣就不會(huì)拋出非法的線程訪問異常了。

            看下效果:
             
            
            下面是完整的類
           
              package com.cnex.oss.managerupdate.tools;
              
              
          import java.beans.PropertyChangeListener;
              
          import java.beans.PropertyChangeSupport;
              
          import java.util.Timer;
              
          import java.util.TimerTask;
              
              
          import org.eclipse.jface.dialogs.IDialogConstants;
              
          import org.eclipse.jface.layout.GridDataFactory;
              
          import org.eclipse.jface.window.Window;
              
          import org.eclipse.swt.SWT;
              
          import org.eclipse.swt.graphics.Image;
              
          import org.eclipse.swt.widgets.Composite;
              
          import org.eclipse.swt.widgets.Control;
              
          import org.eclipse.swt.widgets.Display;
              
          import org.eclipse.swt.widgets.Label;
              
          import org.eclipse.swt.widgets.Shell;
              
              
          /**
               * 定時(shí)執(zhí)行對(duì)話框 。 
               * 
          @author 劉堯興
               * <p>2009-12-7</p>
               
          */
              
          public class TimerMessageDialog extends MessageDialog2 {
              
                
          /** 標(biāo)簽文本     */
                
          protected static Label localMessageLabel;
                
                
          /** 屬性修改支持實(shí)現(xiàn)類     */
                
          private PropertyChangeSupportImpl instance = new PropertyChangeSupportImpl();
              
                
          /** 定時(shí)器     */
                
          private Timer timer;
                
                
          /**
                 * 構(gòu)造函數(shù)。
                 * 
          @param parentShell
                 * 
          @param dialogTitle
                 * 
          @param dialogMessage
                 
          */
                
          public TimerMessageDialog(Shell parentShell, String dialogTitle, String dialogMessage) {
                  
          super(parentShell, dialogTitle, null, dialogMessage, INFORMATION, new String[] {"立即重啟","隱藏"}, 0);
                  setShellStyle(SWT.BORDER 
          | SWT.MIN);
                }
              
                
          protected Control createMessageArea(Composite composite) {
                  
          // create composite
                  
          // create image
                  Image image = getImage();
                  
          if (image != null) {
                    imageLabel 
          = new Label(composite, SWT.NULL);
                    image.setBackground(imageLabel.getBackground());
                    imageLabel.setImage(image);
              
          //      addAccessibleListeners(imageLabel, image);
                    GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.BEGINNING)
                        .applyTo(imageLabel);
                  }
                  
          // create message
                  if (message != null) {
                    messageLabel 
          = new Label(composite, getMessageLabelStyle());
                    TimerMessageDialog.localMessageLabel 
          = messageLabel;
                    messageLabel.setText(message);
                    GridDataFactory
                        .fillDefaults()
                        .align(SWT.FILL, SWT.BEGINNING)
                        .grab(
          truefalse)
                        .hint(
                            convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH),
                            SWT.DEFAULT).applyTo(messageLabel);
                  }
                  
          return composite;
                }
                
                
          /**
                 * 打開定時(shí)關(guān)閉對(duì)話框,顧名思義,就是在指定的時(shí)間自動(dòng)關(guān)閉  。
                 * 
          @author 劉堯興
                 * 
          @param second
                 * 
          @param message 
                 
          */
                
          public void open(final int second,final String message) {
                  setBlockOnOpen(
          false);
                  open();
                  
              
          //    final MessageFormat format = new MessageFormat("系統(tǒng)檢查到重要插件的更新,系統(tǒng)將會(huì)在 {0} 秒后自動(dòng)重啟,請(qǐng)注意保存文件");
                  
                  timer 
          = new Timer("檢查更新");
                  
          final TimerTask task = new TimerTask() {
                    
          int count = second;
                    
          public void run() {
                      Display display 
          = Display.getDefault();
                      
          if (display == null) {
                        
          return;
                      }
                      display.asyncExec(
          new Runnable() {
                        
          public void run() {
                          
          try {
              
                            
          if (count == 0) {
                              cancel();
                              buttonPressed(Window.OK);
                            } 
          else {
                              count 
          -= 1;
                              
          if (!localMessageLabel.isDisposed()&&localMessageLabel != null) {
                                localMessageLabel.setText(message
          +"系統(tǒng)將在:" + count + "秒后自動(dòng)重啟");
              
          //                localMessageLabel.setText(format.format(new Object[]{new Integer(count)}));
                              }
                            }
                          
                          }
          catch (Exception e) {
                            e.printStackTrace();
                          }
                        }
                      });
                    }
                  };
                  timer.schedule(task, 
          10001000);
                }
                
                
          protected void buttonPressed(int buttonId) {
                  
          if(buttonId == Window.OK) {
                    timer.cancel();
                    firePropertyChange(IPropery.RESTART_OK_PRESSED, 
          falsetrue);
                  } 
          else if(buttonId == Window.CANCEL) {
                    close();
                  }
                }
                
                
          /**
                 * 添加屬性事件  。
                 * 
          @author 劉堯興
                 * 
          @param l
                 
          */
                
          public void addPropertyChangeListener(PropertyChangeListener l) {
                  instance.addPropertyChangeListener(l);
                }
                
                
          /**
                 * 刪除屬性修改事件  。
                 * 
          @author 劉堯興
                 * 
          @param l
                 
          */
                
          public void removePropertyChangeListener(PropertyChangeListener l) {
                  instance.removePropertyChangeListener(l);
                }
                
                
          /**
                 * 通知屬性修改事件(通知前臺(tái)代碼修改)  。
                 * 
          @author 劉堯興
                 * 
          @param prop
                 * 
          @param old
                 * 
          @param newValue
                 
          */
                
          public void firePropertyChange(String prop, Object old, Object newValue) {
                  instance.firePropertyChange(prop, old, newValue);
                }
                
                
          /**
                 * 屬性修改支持實(shí)現(xiàn)類  。 
                 * 
          @author 劉堯興
                 * <p>2009-8-18</p>
                 
          */
                
          public class PropertyChangeSupportImpl {
                  
                  
          /** 屬性修改支持     */
                  PropertyChangeSupport listeners 
          = new PropertyChangeSupport(this);
              
                  
          /**
                   * 添加屬性修改事件  。
                   * 
          @author 劉堯興
                   * 
          @param l
                   
          */
                  
          public void addPropertyChangeListener(PropertyChangeListener l) {
                    listeners.addPropertyChangeListener(l);
                  }
              
                  
          /**
                   * 通知修改事件發(fā)生  。
                   * 
          @author 劉堯興
                   * 
          @param prop
                   * 
          @param old
                   * 
          @param newValue
                   
          */
                  
          public void firePropertyChange(String prop, Object old, Object newValue) {
                    listeners.firePropertyChange(prop, old, newValue);
                  }
              
                  
          /**
                   * 通知事件修改  。
                   * 
          @author 劉堯興
                   * 
          @param prop
                   * 
          @param child
                   
          */
                  
          protected void fireStructureChange(String prop, Object child) {
                    listeners.firePropertyChange(prop, 
          null, child);
                  }
              
                  
          /**
                   * 刪除屬性修改事件  。
                   * 
          @author 劉堯興
                   * 
          @param l
                   
          */
                  
          public void removePropertyChangeListener(PropertyChangeListener l) {
                    listeners.removePropertyChangeListener(l);
                  }
                }
              
              }
          posted on 2009-12-09 08:32 VWPOLO 閱讀(2423) 評(píng)論(4)  編輯  收藏

          Feedback

          # re: SWT對(duì)話框系列:倒計(jì)時(shí)關(guān)閉對(duì)話框.doc 2009-12-09 10:24 20G高壓鍋爐管
          說的挺好  回復(fù)  更多評(píng)論
            

          # re: SWT對(duì)話框系列:倒計(jì)時(shí)關(guān)閉對(duì)話框.doc 2009-12-09 11:48 feenn
          中間在說PropertyChangeListener的時(shí)候說錯(cuò)了吧,PropertyChangeListener是java.beans中的接口,代碼中都寫正確了的  回復(fù)  更多評(píng)論
            

          # re: SWT對(duì)話框系列:倒計(jì)時(shí)關(guān)閉對(duì)話框.doc 2009-12-10 10:45 夢芭莎內(nèi)衣
          的大方廣闊的風(fēng)格  回復(fù)  更多評(píng)論
            

          # re: SWT對(duì)話框系列:倒計(jì)時(shí)關(guān)閉對(duì)話框.doc 2009-12-11 16:20 av
          很好的小功能,收藏了!  回復(fù)  更多評(píng)論
            


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 金坛市| 营口市| 兰州市| 楚雄市| 黎川县| 泰和县| 丽水市| 象山县| 彭阳县| 剑川县| 黔西| 山东| 南靖县| 佛冈县| 双辽市| 成武县| 哈密市| 育儿| 晋中市| 江源县| 万安县| 屏南县| 遂川县| 穆棱市| 多伦县| 佳木斯市| 建瓯市| 长白| 油尖旺区| 察雅县| 宜君县| 张家界市| 乐安县| 文成县| 孟村| 武穴市| 永济市| 湖南省| 天台县| 信宜市| 麟游县|