现在的位置: 首页 > 综合 > 正文

SWT窗口预览

2013年01月04日 ⁄ 综合 ⁄ 共 3345字 ⁄ 字号 评论关闭

SWT窗口预览

1.        问题背景

         SWT我就不用多介绍了,SWT已经成为Java桌面端最流行的开发工具,速度快、平台独立、界面美观,替代了Java早期的界面包AWT/Swing。在使用SWT来写界面的时候,一个项目除了程序主界面外,还有很多其他的窗口(或叫做对话框),对话框(Dialog)是呈现数据的最佳方式,所以在一个GUI程序中往往存在大量的界面,也因此有较好的易用性,而且SWT中也提供了一些常用的Dialog类。

         如果每次我们在编写一个窗口类的时候,当完成了一部分代码,想去查看一下这个窗口的效果该怎么办呢?通常的处理方式有两种:

l  在当前窗口类中写main函数,main函数中创建Display, Shell,并创建事件的监听循环,主要代码如下:

public static void main(String[] args){

       Display display = new Display();

       Shell parent = new Shell(display);

       ConfigDlg dlg = new ConfigDlg(parent,SWT.MIN|SWT.CLOSE);

       dlg.open();

       if(!parent.isDisposed()){

           while(!display.readAndDispatch())

              display.sleep();

       }

       display.dispose();

    }

如图上述代码,假设ConfigDlg是我们当时创建的窗口类,把main函数完成之后,直接执行就可以看到窗口的效果了。这个方法是我们最常用的方法。

 

l  另外一种方法是直接启动当前工程的主界面,然后一步一步执行,直到ConfigDlg的父窗口打开,然后点击弹出ConfigDlg窗口。但是存在几个问题:i) 当前工程其他部分还没有完成,所以整个程序可能并不能执行,但是我又想看到当前窗口的效果;ii) 当前程序虽然可以执行,但中间可能还需要完成其他数据输入才能显示对应界面,因此为了进入到该窗口我可能需要输入大量的数据,而就为了这么一个预览窗口的意愿花费了大量不相干的工作;iii) 即使不用输入数据或者数据输入很方便的完成,每次需要一步一步操作,实在琐碎乏味,如果运行多次,我每次做的事情都是一样的、乏味的。

总之,这些方法付出的时间开销、代价都比较大。

 

举例:比如我现在编写了一个配置窗口,类名是ConfigDlg,该窗口是当用户点击配置菜单的时候执行的,因此配置菜单中有一行对应的执行代码:new ConfigDlg().run()。如果我想查看配置窗口的效果,流程是:运行整个项目,启动word->点击菜单,出现下拉菜单->从下拉菜单中选择“配置”,弹出配置窗口。这个过程比较繁琐,每次修改,每次都得重新执行一遍整个流程。

 

2.  我的解决方法

    第一种方法是比较好的方法,但是每次都得重复写10行左右的代码,比较“乏味”,凡当有很多重复的工作量的时候就需要考虑如何使用代码来减少我们平时的一些不必要的重复劳动,让代码“自动化”做些事情。

    对话框能够显示的特点:每个对话框中的执行(显示)的函数是run,一个对话框在创建时传递一个父窗口的Shell变量和窗口风格的参数。

    需要提供的东西:现在最好能提供一个通用的函数,能够被所有的窗口类调用,从而显示当前窗口。因此该函数应该在所有类的“外边”,作为一个类似Utility的方法。假设把该方法叫做preview,该方法位于一个称为PreviewWorkbench的类中。

    解决方案的设计过程:如何使用该方法显示一个窗口?首先窗口需要给该方法传递参数,表明显示的是哪一个窗口。如果直接传递当前窗口的shell,是行不通的,因为shell现在并没有创建,它的创建依赖于一个父窗口的shell,而在调用preview之前,父窗口是并不存在的。而且如果添加一个Shell类型的parent作为preview的参数,那么每次就会把一些“额外工作”交给preview的使用者来完成,这样所花费的工作量跟最传统的方案没有任何区别,还增加了复杂性。所以父窗口的shell应该在preview函数内部创建,用户是不用关心的,而且为了避免歧义,父窗口应该设置为隐藏。好,父窗口如何创建的问题解决了,那么如何显示我们要预览的当前这个窗口呢?其实,除了shell可以唯一标识一个窗口之外,窗口的类名也可以唯一标识该窗口的。因此使用一个字符串参数作为preview的第一个参数,另外一个参数可用来表示该窗口的风格,所以preview的函数原型应该是:public static void preview(String className,int style),其中className是窗口类名,style是窗口显示的风格。

    由于传递进来的是窗口的类名,而且需要首先在preview中完成创建父窗口shell,然后再来创建当前窗口shell,并通过调用open函数显示窗口以及创建事件监听循环等过程,而且将父窗口作为“背景窗口”,只显示要预览的子窗口。分析到这里,大家应该知道了,可以使用Java的反射机制通过类名来创建该类的对象,然后调用该类的其他方法进行创建和显示。具体代码如下:

/**

     * 利用此函数对需要显示的窗口进行预显示,利用的是Java的反射性质,直接传入窗口类名的字符串以及窗口

     * 显示的样式,即可预览该窗口;

     * 注意:需要预览的窗口类必须提供getShell()open()方法;getShell()用于获取shell,当窗口关闭时

     * 后台程序也会随之退出;open()方法用于显示该窗口

     *

     * @param className 窗口类名

     * @param style 显示的样式

     * @throws ClassNotFoundException 如果提供的类名错误,抛出异常

     * @throws NoSuchMethodException 如果调用的方法不存在,抛出异常

     * @throws IllegalArgumentException 如果传递的参数错误,抛出异常

     * @throws InstantiationException 如果实例化该类出现问题,抛出异常

     * @throws IllegalAccessException 如果非法调用某个方法,抛出异常

     * @throws InvocationTargetException 如果newInstanceinvoke等构造函数和成员方法调用出问题,抛出异常

     */

    public static void preview(String className,int style) throws ClassNotFoundException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException{

       Display display = new Display();

       final Shell backgroundShell = new Shell(display,SWT.NONE);

      

       Class c=Class.forName(className);//利用反射,加载该类

       Constructor  cc=c.getConstructor(Shell.class,int.class);//获取以给定类型作为参数的构造函数

       Object object=cc.newInstance(new Object[]{backgroundShell,style});//用带参数的构造函数创建一个实例

      

       Method getShell=c.getMethod("getShell");//获取该窗口的shell

抱歉!评论已关闭.