`
hlbng
  • 浏览: 174626 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

swt界面编程

    博客分类:
  • RCP
阅读更多

(一)

第一步:建立一个Java工程:因为这个是大家都非常熟悉的,所以就不再赘述,你可以建立一个任何名字的Java工程。

第二步:导入swt以及JFace的库文件。这也就意味着:将swt/JFace相关的库文件导入到工程的classpath中去。需要的库文件有哪些呢?打开eclipse安装目录下的plugins文件夹,我们需要找到以下jar文件:
org.eclipse.swt_3.x.x.jar
org.eclipse.jface_3.x.x.jar
org.eclipse.core.runtime_3.x.x.jar
org.eclipse.ui.workbench_3.x.x.jar

这就是我们搭建一个基本swt/eclipse程序所需要基本的一些库文件了。其中3.x.x视你所使用的eclipse版本而定,譬如我的eclipse版本是3.1M6,这些3.x.x就是3.1.0。将他们加入你程序的classpath中。

为了更加清楚地说明如何做,你可以看一下下面的图1。这是我在eclipse的做法:打开工程的properties对话框,然后选择Java Build Path中的Libraries选项卡,将这些jar导入进来。当然你可以有自己的做法。

第三步:为你的java程序添加本地库文件。如果你使用windows的话,你可能注意到在eclipse的plugins目录下还有一个 org.eclipse.swt.win32_3.x.x.jar,将这个jar解压以后在os/win32/x86目录下有几个dll文件。这几个 dll为swt通过JNI访问windows本地API提供了接口,我们需要将使java程序在启动时候即能够访问它。你可以有多种办法实现这个目的:
最简单的办法就是直接把这几个文件拷贝到你jdk的bin目录下
你也可以设定环境变量时候,在PATH中加入这几个dll文件的目录。

你还可以在运行程序时候指定java.library.path为这几个dll所在的目录,在eclipse中,如果你打开Help菜单中 About Eclipse Platform,然后在出现的对话框中选择configuration details按钮,你可以在接下来出现的对话框中找到java.library.path配置java.library.path。你还有另外一种办 法,就是在最后运行程序的时候,从Run菜单中选择Run As..而不是Run As Java Application,填写好必要的其他参数以后打开Argument选项卡,然后在VM Argument输入框中填写该参数为dll文件的路径。

通过这三步工作,你就可以编写swt/JFace程序了。

--------------------------------------------

(二)

package swtjfacesample;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class HelloSWT
{
/**
* Hello,world!
* @param args
*/
public static void main(String[] args)
{
   Display display = new Display();
   Shell shell = new Shell(display);
   Text helloText = new Text(shell, SWT.CENTER);
   helloText.setText("Hello,World!");
   helloText.pack();
   shell.pack();
   shell.open();
  
   while(!shell.isDisposed())
   {
    if(!display.readAndDispatch())
    {
     display.sleep();
    }
   }
   display.dispose();
}
}

 

这段程序虽然很简单,但是它反映了我们书写swt程序的步骤,这些步骤是:
1. 创建一个Display对象
2. 创建一个或者多个Shell对象,你可以认为Shell代表了程序的窗口。
3. 在Shell内创建各种部件(widget)
4. 对各个部件进行初始化(外观,状态等),同时为各种部件的事件创建监听器(listener)
5. 调用Shell对象的open()方法以显示窗体
6. 各种事件进行监听并处理,直到程序发出退出消息
7. 调用Display对象的dispose()方法以结束程序。

Display:与操作系统沟通的桥梁

我们在前面说过,每个swt程序在最开始都必须创建一个Display对象。Display对象起什么作用呢?它是swt与操作系统沟通的一座桥 梁。它负责swt和操作系统之间的通信。它将swt/JFace的各种调用转化为系统的底层调用,控制操作系统为swt分配的资源。同时我们也可以通过 Display对象得到操作系统的一些信息。

Display有着众多的方法,我们不可能一一介绍。在这里只挑选几个可能会比较常用的作一些简单介绍。
setData()和getData():这一对函数允许我们为Display对象设定一些数据,setData()的参数中key和value类似于我们在使用Map                       对象中key和value的含义。
getShells()得到关联到该Display对象的所有没有dispose的Shell对象
getCurrent()得到与用户交互的当前线程
readAndDispatch()得到事件并且调用对应的监听器进行处理
sleep()等待事件发生

Shell:窗口

一个Shell对象就是一个窗口。你可以在上面放置各种部件创建丰富的图形界面。
我们都知道窗口有很多种,比如窗口有可以调整大小的,有不可以的,有的没有最大化最小化按钮。这些窗体的特征在swt中被成为风格(style)。一个窗体的风格可以用一个整数进行定义。这些风格的定义在org.eclipse.swt.SWT中。

Shell对象可用的风格包括:BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE , PLICATION_MODAL, MODELESS, PRIMARY_MODAL,S YSTEM_MODAL
这些风格我们不作一一介绍,你可以从他们字面意义看出一些含义来,当然也可以参考对应的javadoc。

我们可以在一个Shell的构造函数中定义它的风格,比如在前面的Hello,world!程序中,我们可以这样定义Shell。
Shell shell = new Shell(display,SWT.CLOSE | SWT.SYSTEM_MODAL);
最后得到的窗体没有最大化和最小化按钮,并且大小是固定不变的。

因为swt运行于各种平台之上,而这些平台上的窗口管理器千差万别,所以所有这些风格都不是肯定可以实现的。在swt的javadoc中,这被称为暗示(hints)。

Shell对象的方法大都和GUI有关,比如setEnabled()设定了窗体是否能够和用户进行交互,setVisble()设定了窗体是否可见,setActive()将窗体设为当前的活动窗口。

我们可以用open()方法打开一个窗体,close()方法关闭一个窗体。

------------------------------------------

(三)

从Widget和Control开始:

Widget是Control的父类,而Control是我们使用的大多数部件的父类。我们在以前的一些编程语言中可能接触过“控件”或者“组件”之类的概念,部件(widget)的概念大体和这些相当。
在org.eclipse.swt.widgets中定义了众多的widget,甚至我们前面介绍的Shell也被当成widget的一种。
因为可用的widget如此之多,所以我大概没有办法全部一一介绍。在这一节中,我会介绍几种常用的widget。相信善于触类旁通的你通过这些极为简略的介绍应该可以开始使用各种widget,在使用中不断完善自己的认识。

首先我们来介绍Widget。它是一个抽象类,也是所有widget的父类。通过介绍这个类,我们可以得出这所有widget的一些共有特性。

Widget的方法中dispose()方法我们在以前曾经见到过,调用这个方法时候,所谓的接收者(receiver,譬如我们这样写: awidget.dispose(),那么awidget就是接收者,而这句话所处的对象成为调用者或者caller)和接收者中所包含的其他 widget会释放它们所占用底层操作系统的资源。这也就是说你不必显式地为程序中创建的每个widget进行dispose()调用,而只需要确保最外 层的widget(比如Display)进行了dispose()就可以了。

另外还可以通过isDisposed()判断是否该widget(接收者)已经进行了dispose。
Widget中的getStyle()方法得到widget的风格,而getDisplay()得到所处的Display对象。

此外Widget中还有两个重要方法getData()和setData(),这两个方法允许我们为一个widget附加其他的信息。特别是在你需 要跨模块传递widget的时候,这个功能显得非常有用。比如如果一个文本框中显示了一段文章中的某句话,如果我们同时希望把这整篇文章的题目和作者附加 上的话可以这样写:
atext.setData(“title”,”I Have A Dream”);
atext.setData(“author”,” Martin Luther King”);
在程序的其他部分可以用atext.getData(“title”)得到这篇文章的题目,或者用atext.getData(“author”)得到作者。

在前面我们提到过,Control是今后我们所使用大部分widget的父类。在这里我不单独进行介绍,而是在后面的部分中介绍。

创建部件:

和创建其他java object一样,我们通过使用new操作符创建部件的实例。有一点比较特殊的可能你需要使用带参数的构造函数进行new操作。类似下面的程序:
Text text=new Text(shell,SWT.CENTER);
这种方法适用于几乎所有的widget,其中第一个参数是父widget,也就是指明了该widget需要被放置道另外哪一个widget之中,而第二个参数是这个widget的风格。

大小和位置:

仅仅创建一个部件并不足以让你看到它,因为一个部件初始的长和宽都是0。你还需要设定它的大小。你可以用setSize()或者setBounds ()方法手动设定部件的大小,也可以让系统自动调整部件的大小到一个合适的值,这个值也被成为首选尺寸(preferred size)。

可以通过调用pack()方法让系统调整控件大小。如果你希望系统自动调整,那么你需要首先设定控件需要表达的内容。举个例子来说,如果你的部件是一个文本框或者标签,你应该首先设定它所要显示的文本,这样系统可以通过文本的长度计算。

对于部件的位置,同样可以使用setLocation()或者setBounds()进行设定。
这里值得一提的是所谓的bounds,其实bounds可以看成是大小和尺寸的综合。比如setBounds(int x, int y,int width,int height)的参数中,x和y描述的是位置信息,而width和height描述了大小。

隐藏与失效:

通过部件的setVisible方法可以控制部件进行隐藏或是显示。通过setEnabled方法可以控制部件是否有效。一个无效的部件不会对用户的任何动作作出响应。这两个方法的参数都是布尔型的。

提示文本:

可以通过setToolTipText()方法设定部件的提示文本。

几种常用的部件:
Label:

标签用来显示静态的文本或者图像。关于图像和色彩我会在后面的部分进行介绍。
标签可以使用SWT.CENTER, SWT.LEFT, SWT.RIGHT中的一种指明文本的对齐方式(居中对齐,左对齐,右对齐)。
你也可以通过设置标签属性为SWT. SEPARATOR 使标签成为一条分隔符。
下面这个程序给出了标签的两种表现形式,其中使用了Layout,关于Layout的详细情况也会在后面的部分进行介绍:

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.*;

public class HelloSWT
{
public static void main(String[] args)
{
   Display display = new Display();
   Shell shell = new Shell(display, SWT.SHELL_TRIM);
   RowLayout layout = new RowLayout(SWT.VERTICAL);
   shell.setLayout(layout);
   shell.setText("Labels");
   Label label1 = new Label(shell, SWT.CENTER);
   label1.setText("Label Demo");
   Label label2 = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
   shell.setSize(100, 100);
   shell.open();
   while(!shell.isDisposed())
   {
    if(!display.readAndDispatch())
    {
     display.sleep();
    }
   }
   display.dispose();
}
}

 

Text:

Text就是最简单的文本框,与标签一样,我们可以通过设定它的风格来表示它的对齐方式(SWT.CENTER,SWT.LEFT, SWT.RIGHT),另外还有其他一些用于文本支持的方法,比如insert(),paster(),copy(),setSelection(), selectAll()等,这些方法在后面介绍swt事件模式会进行更详细的介绍。

Button:

在swt中,Button并不仅仅是按钮。构造时候定义的风格不同,所体现出的外观也不一样。

如果风格定义成SWT.PUSH,它就是一个普通的按钮。
如果定义为SWT.TOGGLE,它在被按下以后会保持按下的形状(而不会弹起来),直到鼠标再次在上面按一下才会回复弹起的形状。
如果风格定义为SWT.ARROW,它是一个带箭头的按钮,箭头的指向可以选择SWT.LEFT,SWT.RIGHT,SWT.UP,SWT.DOWN中的一个。
如果定义为SWT.CHECK,它是一个复选框。
如果定义为SWT.RADIO,它是一个单选框。

下面一段程序演示了各种不同的Button。

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.*;

public class HelloSWT
{
public static void main(String[] args)
{
   Display display = new Display();
   Shell shell = new Shell(display, SWT.SHELL_TRIM);
   RowLayout layout = new RowLayout(SWT.VERTICAL);
   shell.setLayout(layout);
   shell.setText("Buttons");
   Button pushbutton = new Button(shell, SWT.PUSH | SWT.CENTER);
   pushbutton.setText("SWT.PUSH");
   Button togglebutton = new Button(shell, SWT.TOGGLE | SWT.LEFT);
   togglebutton.setText("SWT.TOGGLE");
   togglebutton.setSelection(true);
   Button arrowbutton = new Button(shell, SWT.ARROW | SWT.LEFT);
   Button checkbox = new Button(shell, SWT.CHECK);
   checkbox.setText("SWT.CHECK");
   Button radio = new Button(shell, SWT.RADIO);
   radio.setText("SWT.RADIO");
   radio.setSelection(true);
   shell.pack();
   shell.open();
   while(!shell.isDisposed())
   {
    if(!display.readAndDispatch())
    {
     display.sleep();
    }
   }
   display.dispose();
}
}

 

---------------------------------------------

(四)

添加事件处理

其实swt中处理事件非常简单,对应于各种事件都有相应的listener类,如果一种事件叫做Xyz,那么对应的listener类就是 XyzListener。比如对应于鼠标事件的有MouseListener,对应于键盘事件的就是KeyListener。而在每种widget中,对 于它可以处理的事件都有addXyzListener方法,只要把对应的listener实例作为参数传给它就可以了。

为了更加清楚的说明,我们先来看下面一段程序:

import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;

public class HelloSWT
{
private Shell shell;

public HelloSWT()
{
   Display display = new Display();
   Shell shell = new Shell(display, SWT.SHELL_TRIM);
   setShell(shell);
   RowLayout layout = new RowLayout();
   shell.setLayout(layout);
   shell.setText("Event demo");
   Button button = new Button(shell, SWT.PUSH | SWT.CENTER);
   button.setText("Click me!");
   button.addSelectionListener(new SelectionListener()
   {
    public void widgetSelected(SelectionEvent event)
    {
     handleSelectionEvent();
    }

    public void widgetDefaultSelected(SelectionEvent event)
    {}
   });
   shell.setBounds(200, 300, 100, 100);
   shell.open();
   while(!shell.isDisposed())
   {
    if(!display.readAndDispatch())
    {
     display.sleep();
    }
   }
   display.dispose();
}

protected void handleSelectionEvent()
{
   MessageBox dialog = new MessageBox(getShell(), SWT.OK
     | SWT.ICON_INFORMATION);
   dialog.setText("Hello");
   dialog.setMessage("Hello,world!");
   dialog.open();
}

/**
* @param args
*/
public static void main(String[] args)
{
   HelloSWT eventdemo = new HelloSWT();
}

/**
* @return Returns the _shell.
*/
public Shell getShell()
{
   return shell;
}

/**
* @param _shell The _shell to set.
*/
public void setShell(Shell shell)
{
   this.shell = shell;
}
}

 

你可以看到在这段程序中,我们只创建了一个Button,随后调用了它的addSelectionListener()方法,在这个新创建的Listener,我们只为widgetSelected方法添加了代码,并在其中创建了一个对话框。实际运行效果如下图,其中那个标有Hello,world的对话框是按了按钮以后出现的:

如果总结一下,我们可以得出处理事件的几个步骤:
1. 针对你所处理的事件,找出合适的XyzListener接口
2. 编写一个新的类,这个类实现了XyzListener接口
3. 在你所感兴趣的事件中编写处理代码,而对于那些你不感兴趣的方法可以让它们保持空白(就像实例中的   widgetDefaultSelected()方法)一样

/*如果使用了layout,则不能手动改变button的大小。*/

让事件处理更加简单,使用适配器(adapter):

有时候我们可能会感觉这样仍然不够简单,比如我只对SelectionListener中的widgetSelected()方法感兴趣,但是为了 能够通过编译器的编译,我却不得不写一个空白的widgetDefaultSelected()方法(因为SelectionListener是一个接 口,你必须实现它所有的方法)。
幸运的是,swt帮我们解决了这个问题,途径就是使用adapter。在swt中,对应于一个 XyzListener都有一个XyzAdapter,adapter都是抽象类并且实现了对应的listener接口,它为对应listener接口中 的每个方法都定义了一个默认实现(基本上就是什么都不做),我们在使用时候只需要override掉自己感兴趣的方法就可以了。
结合上一小节中的代码,如果使用SelectionAdapter代替SelectionListener的话,我们的代码就可以这样写:

EventObject,事件处理的附加信息:

在处理各种事件时,我们需要一些附加信息,而EventObject给我们提供了这些信息。
我们先来看下面这个简单的小程序,在这段程序中,我们创建了两个文本框,当在第一个文本框输入时,第二个文本框中显示输入的字符。

import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;

public class HelloSWT
{
Text logText;

public HelloSWT()
{
   Display display = new Display();
   Shell shell = new Shell(display, SWT.SHELL_TRIM);
   GridLayout layout = new GridLayout();
   layout.numColumns = 2;
   shell.setLayout(layout);
   shell.setText("Event demo");
   Label label1 = new Label(shell, SWT.RIGHT);
   label1.setText("text1:");
   Text text1 = new Text(shell, SWT.NONE);
   text1.addKeyListener(new KeyAdapter()
   {
    public void keyPressed(KeyEvent e)
    {
     Text t = getLogText();
     String s = t.getText();
     t.setText(String.valueOf(e.character));
    }
   });
   Label label2 = new Label(shell, SWT.RIGHT);
   label2.setText("text2:");
   Text text2 = new Text(shell, SWT.NONE);
   text2.setEditable(false);
   text2.setBackground(new Color(display, 255, 255, 255));
   setLogText(text2);
   shell.pack();
   shell.open();
   while(!shell.isDisposed())
   {
    if(!display.readAndDispatch())
    {
     display.sleep();
    }
   }
   display.dispose();
}

/**
* @param args
*/
public static void main(String[] args)
{
   HelloSWT demo2 = new HelloSWT();
}

/**
* @return Returns the logText.
*/
public Text getLogText()
{
   return logText;
}

/**
* @param logText The logText to set.
*/
public void setLogText(Text logText)
{
   this.logText = logText;
}
}

 

在这段代码中,我们使用了KeyAdapter来处理键盘事件,而keyPressed会在有键按下时候被调用,我们在函数中使用了KeyEvent类型的参数e,并且通过e.character得到了按下键对应的字符。

 

各种EventObject(例如上面示例中的KeyEvent)在事件处理函数中作为参数出现,它们可能有不同的属性和方法,利用这些特性我们可以做很多有意思的事情。
我 们下面只简单介绍几种EventObject,它们分别是对应于窗口事件(ShellListener,ShellAdapter)的 ShellEvent,对应于键盘事件(KeyListener,KeyAdapter)的KeyEvent和对应于鼠标事件 (MouseListener,MouseAdapter)的MouseEvent。希望可以起到窥一斑而见全豹的作用。

几种EventObject简介
ShellEvent:

如果你打开ShellEvent的API,你会很惊讶的发现它只有一个布尔型的属性,就是doit。这个莫名其妙的属性是用来做什么的呢?
我 们知道,Shell对应的就是程序的窗口,在ShellListener中定义的几种事件包括窗口激活时候的shellActivated,窗口即将被关 闭时候的shellClosed等等。ShellEvent中唯一的属性doit,就是用来设定是否这些动作将有效的。
再说得具体一些,比如 Windows下通常我们会通过点击窗口右上角的关闭按钮来关闭窗口,这个时候就会对shellClosed进行调用,如果我们在shellClosed (ShellEvent e)方法中把ShellEvent对象e的doit属性置为了false,那么这次动作就无效,窗口不会被关闭。

在有些其他的EventObject中也有doit属性,它们的作用都是类似的。比如KeyEvent就有这样的一个属性。如果你在keyPressed方法中把它置为了false,就等于你按键盘(对于对应的widget,也就是receiver来讲)没有用。

KeyEvent:

其实在前面我们或多或少的已经介绍了一些KeyEvent的知识。KeyEvent包含四个属性:character,doit,keyCode和stateMask。
其中character我们在前面的示例中使用过,它其实就是按键对应字符,而doit和ShellEvent中的doit含义是相同的。
keyCode是我们称为键码的东西,什么是键码呢?如果你打开org.eclipse.swt.SWT的API文档,你会发现里面有很多都和键盘有关的整型常量,比如SWT.F1,SWT.F4,SWT.ESC,SWT.KEYPAD_3之类,这就是他们的键码。
而stateMask则是用来检测Alt,Shift,Ctrl这些键有没有同时被按下。
用stateMask与这些键的键码进行位与运算,如果得到的结果不是0就说明这些键被按下了,比如如果stateMake & SWT.ALT不为零,我们就可以认为Alt键被按下了。

MouseEvent:

MouseEvent对应于的是鼠标事件。它同样包含四个属性:button,stateMask,x,y
button就是说明按下的是哪个键,比如对于普通鼠标来说,1是左键,2是右键等等
stateMask却是用来反映键盘的状态的,这和KeyEvent中的stateMask含义是相同的。
x和y指的是相对于部件的横坐标和纵坐标。
你可能会觉得有点疑问,光是这么一点属性就能处理鼠标事件了么?如果我有一个滚轮鼠标,那应该用什么事件处理滚轮的动作呢?答案是:目前可能还无法利用事件模式处理,关于这一点可以参照一下这个url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=58656

Untyped Events:

我们在这里提到了untyped events,那肯定就有typed event,typed和untyped本身并不是说事件有什么不一样,而是说事件处理是使用了特定的Listener还是没有。我们前面提到的所有事件 处理都是typed 类型,因为它们都使用了特定Listener。

所谓的untyped events你可以理解为一个事件的大杂烩。和untyped event相联系的两个类是Listener和Event。在这里我想请大家注意一下,这两个类不是在org.eclipse.swt.events中, 而是在org.eclipse.swt.widgets中。
Listener只有一个方法handleEvent,这个方法里你可以处理任何事 件。而如果你打开Event看一下,就能看到我们刚刚在前一小节中介绍过的那些XxxEvent中的属性在这里应有尽有。所以它可以起到替代它们的作用, 当然如果是一个窗口被关闭的事件,相信你用keyCode属性意义不大。

让我们看一下下面一段代码

import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;

public class HelloSWT
{
public HelloSWT()
{
   Display display = new Display();
   Shell shell = new Shell(display, SWT.SHELL_TRIM);
  
   Listener listener = new Listener()
   {
    public void handleEvent(Event e)
    {
     switch(e.type)
     {
     case SWT.Resize:
      System.out.println("Resize received");
      break;
     case SWT.Paint:
      System.out.println("Paint received");
      break;
     default:
      System.out.println("Unknown event received");
     }
    }
   };
   shell.addListener(SWT.Resize, listener);
   shell.addListener(SWT.Paint, listener);
  
   shell.pack();
   shell.open();
   while(!shell.isDisposed())
   {
    if(!display.readAndDispatch())
    {
     display.sleep();
    }
   }
   display.dispose();
}

/**
* @param args
*/
public static void main(String[] args)
{
   HelloSWT demo2 = new HelloSWT();
}
}

 

由此我们大体上可以体会到untyped events的处理方式。

----------------------------------------------

(五)

在eclipse中,你可以使用Visual Editor来进行拖放式的图形界面设计。实际上我觉得在这一方面大家应该可以很容易上手。

如果你安装了VE的话,在新建一个swt工程的时候你就可以省好多力气了:你不需要找那些名字n长的jar,然后一个一个导入工程的build path里面,而是仅仅需要添加一个User Library,就像下面图示一样:

你可以新建一个Visual Class。之后就可以使用VE进行可视化的编辑了。关于VE的具体应用,我在这里不作具体介绍(说实话,我觉得用起来还是比较简单的),如果你觉得实在 有必要看一篇详细的指南的话,可以参照这篇文章:Extending The Visual Editor Tutorial: Enabling support for a custom widget

----------------------------------------------

(六)

使用Layout管理UI布局

我们在前面在一些例子中已经使用过Layout了。那么Layout到底是做什么的呢?

我们知道,在设计用户界面时候,我们可以采用的一种办法是手动的为每个部件设置合适当大小和位置。但是这样的话,如果你所要显示的部件比较多,编程 量就会非常大,特别是考虑到窗体大小变化时候各种部件的重绘。而实际上,我们可以利用一些通用的规则或者说算法来安排这些部件的排列。

很显然,对于这些规则化的部件排列,应该有一些更简单的办法,而不是在代码的各个部分写xxx.setBounds之类。swt给我们提供了这样的办法,就是使用Layout。

你可以把一个Layout看成是安排部件位置和大小的一个规则,在应用了Layout的Composite(我们在这里第一次提到了 Composite,Composite就是一个能够包含其他控件的容器,比如Shell就是一个Composite,我们会在后面的部分详细介绍 Composite)中,所有的子控件都会按照这个规则来进行排列。

在目前(写这篇文章的时候eclipse最新版本是3.1M7),org.eclipse.swt.layout包中包含四种已经定义好的 Layout,它们分别是:FillLayout,FormLayou,GridLayout和RowLayout。我在这里不再一一作介绍,而是推荐大 家看一下这篇文章《Understanding Layouts in SWT》。相信如果你有兴趣看完它的话,就会对Layout有比较深的了解。

----------------------------------------------

(七)

几种特殊的部件
Composite:

其实我们已经接触过Composite了,我们前面介绍过Shell,Shell就是一种特殊的Composite。就如它的名字一样,Composite指的是可以嵌套其他部件的一种部件。
我们先来看一段代码,为了看起来更简明,我把shell创建之类的代码都去掉了。

Composite composite=new Composite(shell,SWT.V_SCROLL);
composite.setLayout(new RowLayout(SWT.VERTICAL));
Text text=new Text(composite,SWT.NONE);
text.setSize(100,30);

这段程序意义不大,不过我们可以看出,Composite可以作为其他部件的parent,可以有自己的Layout。
我们在其中定义composite的风格时候用到了SWT.V_SCROLL,这是用来做什么的呢?它是用来定义这个部件有纵向滚动条的。当然相应当SWT.H_SCROLL就定义了部件有横向滚动条。
那么什么样的部件可以有滚动条呢?只要是org.eclipse.swt.widgets.Scrollable的子类就可以使用这两个风格定义自己的滚动条。这是我们顺便提到的一点题外话。
如果你把上面的程序填充完整运行一下的话会发现出来的样子很难看。因为Composite本身是看不到的。而可以孤零零地看到一个突出的滚动条在那里。所以实际上单独使用Composite意义不是很大,我们可以使用它的一些子类。

打开Composite的javadoc,你会发现它的子类实在是太多了。我们只拣两个介绍一下,Group和TabFolder。
比起Composite来,Group有一个边框,你可以用setText方法设定它的标题。所以这样在视觉上会更好看一些。
另外一种特殊Composite就是TabFolder,TabFolder允许我们定义标签页式的窗体。

我们怎么设定各个标签呢?答案是使用TabItem。可以使用TabItem的setControl方法设定标签页上的控件。但是这样又出现了一个 疑问,setControl中的参数不是数组,如果我们想设定好几个控件应该怎么办呢?这个时候就用得上Composite了。我们可以首先建一个 Composite实例,然后在里面添加控件,再把这个Composite实例本身作为参数传递给TabItem的setControl方法。

为了更清楚地说明,我们可以看一下下面这段代码:

import java.awt.GridLayout;
import org.eclipse.swt.*;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.*;

public class HelloSWT
{
/**
* @param args
*/
public static void main(String[] args)
{
   Display display = new Display();
   Shell shell = new Shell(display, SWT.DIALOG_TRIM);
   shell.setLayout(new RowLayout(SWT.HORIZONTAL));
   shell.setText("TabFolder Demo");
   TabFolder tf = new TabFolder(shell, SWT.NONE);
   tf.setLayout(new FillLayout());
   TabItem ti = new TabItem(tf, SWT.NONE);
   ti.setText("A Simple TalItem");
   Composite composite = new Composite(tf, SWT.NONE);
   composite.setLayout(new GridLayout(2,true)); // wrong
   for(int i = 0; i < 3; i++)
   {
    Label label = new Label(composite, SWT.RIGHT);
    Text text = new Text(composite, SWT.NONE);
    label.setText("Text" + i + ":");
   }
   ti.setControl(composite);
   shell.pack();
   shell.open();
   while(!shell.isDisposed())
   {
    if(!display.readAndDispatch())
    {
     display.sleep();
    }
   }
   display.dispose();
}
}

 

菜单(Menu):

swt中和菜单相关的两个类是Menu和MenuItem。顾名思义,Menu代表的就是整个菜单,而MenuItem是菜单中一项一项的实体。

创建菜单:如果我们要创建一个菜单,可以根据下面步骤来进行:

1. 实例化一个Menu对象,Menu有好几种格式的构造函数,你可以选择一个,比如像这样:
    Menu menu=new Menu(shell,SWT.BAR);
    与其他部件不同的是,Menu的父控件并不一定需要是Composite,而是任何一个Control都可以。而Menu的风格有几种:
    SWT.POP_UP:弹出式菜单
    SWT.BAR:程序中的顶级菜单,比如我们通常看到的包含了“文件,编辑”之类的那个横列的菜单栏
    SWT.DROP_DOWN:下拉式菜单,比如我们在Word点击“文件”之后出现的子菜单就是一个典型的下拉式菜单。

    注意Menu本身是没有setText方法的,因为这些具体的显示属性你必须在相应当MenuItem中设定。

2. 为Menu添加MenuItem对象,一个MenuItem的构造函数如下所示:
    MenuItem(Menu parent, int style)或者MenuItem(Menu parent, int style, int index)
    其中parent就是所属的Menu,而index可以看成是排列顺序。而style可以有以下几种:
    SWT.PUSH:就是一个普通道菜单项,但是这样的MenuItem不能有层叠的下一级菜单
    SWT.CASCADE:这样的MenuItem可以有层叠的下一级菜单。可以使用MenuItem的setMenu方法设定它的下一级菜单,作为参数的     Menu风格必须是SWT.DROP_DOWN
    SWT. SEPARATOR:分隔符,也就是一道横线,这样的MenuItem是没有文字的,所以setText不起作用。
    SWT.CHECK:菜单项前面有一个复选标志。
    SWT.RADIO:菜单项前面有单选标志。

3. 为有下级菜单的MenuItem(风格必须为SWT.CASCADE)设定下级菜单的Menu对象(用setMenu方法),当然了,你仍然需要为    这个下一级的Menu设定其中的MenuItem

4. 如果你的菜单风格式SWT.BAR,你还需要调用Shell的setMenuBar(参数就是顶级菜单)方法设定窗体菜单。如果是弹出式菜    单也就是SWT.POP_UP,你需要调用所在控件的setMenu方法设定弹出菜单为该菜单。

下面这段简单的代码展示了一个只有退出程序功能的文件菜单。

import org.eclipse.swt.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;

public class HelloSWT
{
private Shell shell;

/**
* @return Returns the shell.
*/
public Shell getShell()
{
   return shell;
}

/**
* @param _shell The _shell to set.
*/
public void setShell(Shell shell)
{
   this.shell = shell;
}

public HelloSWT()
{
   Display display = new Display();
   Shell shell = new Shell(display, SWT.SHELL_TRIM);
   setShell(shell);
   shell.setLayout(new RowLayout(SWT.HORIZONTAL));
   shell.setText("Menu Demo");
   Menu menubar = new Menu(shell, SWT.BAR);
   MenuItem fileitem = new MenuItem(menubar, SWT.CASCADE);
   fileitem.setText("&File");
   Menu filemenu = new Menu(shell, SWT.DROP_DOWN);
   fileitem.setMenu(filemenu);
   MenuItem exititem = new MenuItem(filemenu, SWT.PUSH);
   exititem.setText("&Exit");
  
   exititem.addSelectionListener(new SelectionAdapter()
   {
    public void widgetSelected(SelectionEvent arg0)
    {
     MessageBox messagebox = new MessageBox(getShell(), SWT.YES
       | SWT.NO);
     messagebox.setText("Exit");
     messagebox.setMessage("Exit the program?");
     int val = messagebox.open();
     if(val == SWT.YES)
     {
      getShell().close();
     }
    }
   });
  
   shell.setMenuBar(menubar);
   shell.setSize(800, 300);
   shell.open();
  
   while(!shell.isDisposed())
   {
    if(!display.readAndDispatch())
    {
     display.sleep();
    }
   }
   display.dispose();
}

public static void main(String[] args)
{
   HelloSWT demo = new HelloSWT();
}
}

 

加速键:

在使用MenuItem的setText方法时,可以在希望设为加速键的字母前面标&,比如exititem.setText("&Exit");
就标明了这个退出菜单项的加速键为E。
另外也可以使用setAccelerator方法设定加速键。

分享到:
评论

相关推荐

    SWT界面编程知识汇总

    对一些swt的界面设计的知识点的汇总整理。

    Java socket编程,SWT界面显示

    Java socket编程使用SWT编写界面,远程升级程序.class文件,不是工程源码,工程里面还有其他的,不方便发。https://blog.csdn.net/L_e_c/article/details/110423909

    java swt 教程

    这是关于讲解java swt 界面编程的教程,swt是eclipse出的java界面编程包,很好用

    JAVA SWT 制作的标准计算器

    本人自己设计制作的计算器,使用java语言,SWT界面编程,模仿微软计算器。功能强大。

    SWT 图形编程全接触

    Java 世界的人似乎一直都对 Java 的桌面应用程序十分不满,从 AWT 到 SWING,从默认的 Theme到第三方的产品,不是太难看(AWT)就是在某些平台有 BUG... 4 SWT与OpenGL编程 5 结束语 关于作者 对本文的评价

    JAVA SWT 制作的标准计算器(改进版)

    本人自己设计制作的计算器,使用java语言,SWT界面编程,模仿微软计算器。功能强大。

    Java+SWT+图形用户界面教程+PDFJava实用源码整理learns.

    Java+SWT+图形用户界面教程+PDFJava实用源码整理learns.

    如何进行Java GUI图形用户界面编程

    AWT中文译为抽象窗口工具包,是Java提供的用来建立和设置Java的图形用户界面的基本工具。AWT由Java中的java.awt包提供,里面包含了许多可用来建立与平台无关的图形用户界面的类,这些类被称为组件。Java Swing是Java...

    swt-api swt DOC

    swt-api java swt GUI java界面编程,swt的开发DOC,谁用谁知道,一般人我不告诉他

    一款Eclipse的SWT插件

    WBPro_v7.2.0_for_Eclipse3.5 一款Eclipse的SWT插件,可视化编辑界面,打包,带注册 Eclipse3.5要用Eclipse EE 版的,不然好像安装不了

    Eclipse SWT JFace核心应用相关应用及源码.rar

    基于 Java 桌面程序开发的...本书主要讲解了如何使用 SWT 和 JFace 进行应用程序的开发,通过本书系统而全面的 SWT/JFace 知识学习,将帮助读者快 速开发出完美、实用的 GUI 程序,轻松完成繁琐的界面、菜单编程。 本

    java SWT框架代码示例

    SWT是一种java可视化界面编程框架,想学习的人可以下载研究

    SWT/JFace的核心应用与实战教程的PDF电子版.rar

    基于 Java 桌面程序开发的图形库...本书主要讲解了如何使用 SWT 和 JFace 进行应用程序的开发,通过本书系统而全面的 SWT/JFace 知识学习,将帮助读者快 速开发出完美、实用的 GUI 程序,轻松完成繁琐的界面、菜单编程.

    JFace_SWT_win32.x86_64_3.106.2.v20171129-0543.jar(修正版)

    JFace是建立在SWT之上的UI部件,是Eclipse组织为了开发Eclipse IDE环境所编写的一组底层图形界面 API,其底层实现为SWT。它扩展了 SWT并能与 SWT 交互操作。JFace工具箱提供了一组功能强大的用户界面组件,开发人员...

    swt.zip_SWT_swing

    swt 界面设计SWT(Standard Widget Toolkit) Standard Widget Toolkit是一个开源的GUI编程框架,与AWT/Swing有相似的用处,著名的开源IDE-eclipse就是用SWT开发的。 在SWT之前,Sun已经提供了一个跨平台GUI开发工具包...

    java SWT designer插件

    不解释 适合eclipse3.4的platform 版本的可视化图形界面编程 你懂的 不解释 序列号:WindowBuilderPro-03573-0222 注册码:WindowBuilderPro-MP0ZH-NM0J5-7QXU4

    Java Swing 界面美化包-含源码

    一款JAVASE编程的皮肤美化界面插件包 Java Swing 界面美化包-含源码

    Java高手真经(编程基础卷)光盘全部源码 免积分

    javaswt.zip 19.SWT图形界面开发——Java文本编辑器 javajface.zip 20.SWT增强组件库JFace 第5部分(5个程序包) javaapplet.zip 21.Applet网络组件——电子相册 javanet.zip 22.Java网络编程详解(Socket/UDP...

Global site tag (gtag.js) - Google Analytics