是不是觉得Windows的倒计时关机对话框很酷?
??
? 其实你也可以通过SWT的对话框来实现这个功能,如果你真的够无聊的话,可以用来吓唬一下你的用户,当然你的确定你的人缘很好才行.
?? 好了,开场白到此为止,下面进入正题:
<!--endfragment-->??? 我设计这个倒计时对话框主要是为了让我们系统在自动更新完成后自动重启,我们的系统提供了自动更新的功能,而且有个数据传输模块,数据传输模块是使用Wrapper这个工具封装Java程序成服务,数据传输模块会共享RCP客户端的插件Jar包,由于Eclipse插件的特殊性,自动更新完成后可能会在安装目录中存在同名称但不同版本号的插件,具体细节省去7443个字节。
?? 想实现倒计时对话框,我们可以使用Timer这个定时工具类,这主要考虑到倒计时对话框要和RCP项目的主线程区分开来,对话框弹出不能够影响用户的操作,至少得让他们的有时间保存信息不至于丢失,我们把这个类命名为 TimerMessageDialog .java,?根据MessageDialog中提供的方法,我们无法动态显示提示信息,比如还剩下多少时间.你可以重载MessageDialog的 createMessageArea(Composite?composite) 方法,可以再TimerMessageDialog中新增一个字段引用 messageLabel ,比如 localMessageLabel ,然后对 localMessageLabel 的值进行修改,下面是我的实现,可以参考一下:
?
?
? 因为我是在RCP的非UI现在调用这个对话框,所以需要在Display的asyncExec方法启用一个新的异步线程.这样就不会抛出非法的线程访问异常了。
? 看下效果:
下面是完整的类
????
???? 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;
????
???? /**
?????*?定时执行对话框?。?
?????*? @author ?刘尧兴
?????*?<p>2009-12-7</p>
????? */
???? public ? class ?TimerMessageDialog? extends ?MessageDialog2?{
????
?????? /** ?标签文本????? */
?????? protected ? static ?Label?localMessageLabel;
??????
?????? /** ?属性修改支持实现类????? */
?????? private ?PropertyChangeSupportImpl?instance? = ? new ?PropertyChangeSupportImpl();
????
?????? /** ?定时器????? */
?????? private ?Timer?timer;
??????
?????? /**
???????*?构造函数。
???????*? @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( true ,? false )
??????????????.hint(
??????????????????convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH),
??????????????????SWT.DEFAULT).applyTo(messageLabel);
????????}
???????? return ?composite;
??????}
??????
?????? /**
???????*?打开定时关闭对话框,顾名思义,就是在指定的时间自动关闭??。
???????*? @author ?刘尧兴
???????*? @param ?second
???????*? @param ?message?
??????? */
?????? public ? void ?open( final ? int ?second, final ?String?message)?{
????????setBlockOnOpen( false );
????????open();
????????
???? // ????final?MessageFormat?format?=?new?MessageFormat("系统检查到重要插件的更新,系统将会在?{0}?秒后自动重启,请注意保存文件");
????????
????????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 + " 系统将在: " ? + ?count? + ? " 秒后自动重启 " );
???? // ????????????????localMessageLabel.setText(format.format(new?Object[]{new?Integer(count)}));
????????????????????}
??????????????????}
????????????????
????????????????} catch ?(Exception?e)?{
??????????????????e.printStackTrace();
????????????????}
??????????????}
????????????});
??????????}
????????};
????????timer.schedule(task,? 1000 ,? 1000 );
??????}
??????
?????? protected ? void ?buttonPressed( int ?buttonId)?{
???????? if (buttonId? == ?Window.OK)?{
??????????timer.cancel();
??????????firePropertyChange(IPropery.RESTART_OK_PRESSED,? false ,? true );
????????}? 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);
??????}
??????
?????? /**
???????*?通知属性修改事件(通知前台代码修改)??。
???????*? @author ?刘尧兴
???????*? @param ?prop
???????*? @param ?old
???????*? @param ?newValue
??????? */
?????? public ? void ?firePropertyChange(String?prop,?Object?old,?Object?newValue)?{
????????instance.firePropertyChange(prop,?old,?newValue);
??????}
??????
?????? /**
???????*?属性修改支持实现类??。?
???????*? @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);
????????}
????
???????? /**
?????????*?通知修改事件发生??。
?????????*? @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);
????????}
??????}
????
????}
???? // ?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( true ,? false )
??????????.hint(
??????????????convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH),
??????????????SWT.DEFAULT).applyTo(messageLabel);
????}
???? return ?composite;
??}
?? 然后我们添加一个打开对话框的方法: ?open(final?int?second,final?String?message) ,second表示倒计时时间,message表示提示信息,在open方法中新建一个 Timer 对象。对了,为了让MessageDialog弹出后不阻塞线程的执行,需要在调用对话框的open方法之前调用 setBlockOnOpen(false); 方法,下面是我的实现,大家可以参考一下:
???*?打开定时关闭对话框,顾名思义,就是在指定的时间自动关闭??。
???*? @author ?刘尧兴
???*? @param ?second
???*? @param ?message?
??? */
?? public ? void ?open( final ? int ?second, final ?String?message)?{
????setBlockOnOpen( false );
????open();
????
// ????final?MessageFormat?format?=?new?MessageFormat("系统检查到重要插件的更新,系统将会在?{0}?秒后自动重启,请注意保存文件");
????
????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 + " 系统将在: " ? + ?count? + ? " 秒后自动重启 " );
// ????????????????localMessageLabel.setText(format.format(new?Object[]{new?Integer(count)}));
????????????????}
??????????????}
????????????
????????????} catch ?(Exception?e)?{
??????????????e.printStackTrace();
????????????}
??????????}
????????});
??????}
????};
????timer.schedule(task,? 1000 ,? 1000 );
??}
?
?? 这里的Timer是每一秒钟执行一次,在定时器执行完成后应该让对话框自动关闭,然后可以通知事件发起人来执行对应的操作,从这样设计的角度上看,我们的需要在用户点击确认或者取消或者关闭对话框时响应用户的操作,这样我们的重载父类的 buttonPressed(int?buttonId) 方法,在这个方法中执行对应的操作.比如这样:
?
???? if (buttonId? == ?Window.OK)?{
??????timer.cancel();
??????firePropertyChange(IPropery.RESTART_OK_PRESSED,? false ,? true );
????}? else ? if (buttonId? == ?Window.CANCEL)?{
??????close();
????}
??}
?? 这里我使用了java.util包中的
PropertyChangeListener
来监听属性值的修改。这里的对话框应该算是事件源,由这个发起属性事件的修改通知,其他监听类根据接收到的信息作出相应的响应。我在TimerMessageDialog实现了一个内部类:
PropertyChangeSupportImpl
,这个类管理通知的对象:
?
?
<!--endfragment-->
???*?属性修改支持实现类??。?
???*? @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);
????}
???? /**
?????*?通知修改事件发生??。
?????*? @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);
????}
??}
?? 在完成这些之后,在监听类中注册一个属性修改的事件,比如在UpdatePlan这个类中执行TimerMessageDialog的打开操作,那就的让UpdatePlan这个类实现 PropertyChangeListener 这个接口并实现 propertyChange(final?PropertyChangeEvent?evt) 这个方法,这个方法可以根据传过来的属性名称和属性值执行相应的操作。UpdatePlan属性注册方式是:
??????@Override
?????? public ? void ?run()?{
???????? try ?{
??????????TimerMessageDialog?dialog? = ? new ?TimerMessageDialog(Display.getDefault().getActiveShell(), " 系统信息 " , " 系统将要自动重启 " );
??????????dialog.addPropertyChangeListener( this );
??????????dialog.open( 30 , "" );
????????}
???????? catch ?(Exception?e)?{
??????????e.printStackTrace();
????????}
??????}
????});