您的位置:首页 > 其它

SWT高级主题第二部分

2012-07-19 16:58 423 查看
SWT高级主题(Standard Widget Toolkit)第二部分
在SWT基础中,我们简要的了解了SWT的产生背景,开发SWT应用程序的基本要求以及基本的SWT组件以及部分事件监听器。本部分内容将介绍一些高级的组件,布局管理器等高级主题。
高级组件:
图形:SWT提供了丰富的图形功能。这些功能大部分以GC类为核心。
图形上下文(Graphics Context,或者GC)类用来进行绘图和显示图片。它提供了大量的基本的图形功能,包括如下的功能:
绘画或者填充矩形,圆形,线,多边形或者文本。
设置背景色或者前景色
设置clipping区域
将某个区域拷贝到图片或者同一组件的其他区域
显示图片
设置或者获取文本/字体属性
注:几乎可以为所有的组件获取GC,然后在组件上面进行绘图。本文中以Canvas为例进行说明。
可以通过标准的构造方法创建Canvas对象,然后设置其大小和位置。
Canvas canvas = new Canvas(shell, SWT.BORDER);
canvas.setSize(300,300);
canvas.setLocation(20, 20);
接下来需要打开shell,这是很关键的一步,因为如果shell没有打开的话,那么在Canvas上绘制的图形不会被显示。
shell.open();
为特定的组件获取GC的方法如下:
GC gc = new GC(canvas);
此时GC只应用于Canvas对象,任何绘图操作都会反映到canvas上面。也就是说,如果绘制的图形超过了canvas的界限,那么不会被显示。最基本的任务就是绘制和填充矩形。可以通过drawRectangle和fillRectangle来实现。drawRectangle使用当前的前景色(黑色)来绘制矩形,参数x,y表示矩形的坐标,然后是矩形的宽和高。
gc.drawRectangle(3, 5, 20, 25);
fillRectangle方法和其类似,只是填充的颜色是当前的背景颜色(灰色)。由于没有设置背景颜色,所以绘制填充后的矩形不可见。
获取颜色的最简单的办法就是使用Display类的getSystemColor方法,以SWT的颜色常量作为参数。
Color blue = display.getSystemColor(SWT.COLOR_BLUE);
Color red = display.getSystemColor(SWT.COLOR_RED);
也可以手动创建Color对象。
获取颜色之后就可以设置GC的前景色和背景色了。注:fill方法还可以用于填充Oval和Polygon。对于Oval来说,指定的参数是圆形的外切圆,对于多边形来说,int数组中的值是点的坐标。
gc.setForeground(blue);
gc.drawLine(80, 20, 100, 80);
gc.drawOval(40, 40, 10, 10);
gc.drawPolygon(new int[] {100, 100, 120, 120, 140, 100});//(100,100),(120,120),(140,100),是一个三角形
注:填充矩形和绘制矩形的大小是不一样的,填充矩形的大小要比绘制矩形小一行和一列。
另一个比较有用的功能就是绘制文本,通过drawString方法来完成,并且可以指定文本的坐标。另外,可以指定文本是否透明。
同时,还可以设置clipping区域,这样绘制操作就被限制在组件的特定的clipping window中。可以通过setClipping方法来完成。下面的代码clip园的特定的区域。
gc.setClipping(40, 60, 40, 40);
gc.fillOval(30, 50, 30, 25);

SWT库中提供了非常多的图形类使用在操作系统级分配的资源,所以需要程序员来进行显式的释放。所以在上面的代码中,当shell被关闭的时候,GC必须被释放:
gc.dispose();
这行代码可以放在绘制完成的最后一行。用完即释放图形对象是一个好的原则。以下的对象经常需要显式的释放:Color,Image,Fonts。在上例中,并没有显式释放Colors对象blue和red,这是由于它们是预分配的系统颜色。一个通用的原则是如果是你创建的,那么你负责释放,否则的话,不需要进行释放。
GC类还有很多方法,例如设置线条的宽度,获取文本的字体,拷贝组件的区域等等,详细内容,请参考SWT的javadocs。
repaint:上面的例子中还有一个缺点,就是当窗口被最小化,或者拖动窗口,使图形被挡住之后,canvas的一部分就被挡住了,即原有的图形不能显示。这是由于只是在程序开始的时候进行了图形的绘制,而没有进行重画(repaint)。
为了确定canvas什么时候需要被重画,必须追加PaintListener给它。下面的代码将重画矩形,无论是否被遮挡。
Canvas canvas = new Canvas(shell, SWT.BORDER);
canvas.setSize(150, 150);
canvas.setLocation(20, 20);
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
GC gc =e.gc;
gc.drawRectangle(3, 5, 20, 25);
}
});

shell.open();
PaintListener会检测到canvas被重画,然后执行paintControl方法来绘制矩形。注:shell.open方法出现在监听器后面,因为初始的绘制是在shell打开的时候被完成的。如果将PaintListener添加在shell.open后面,那么除非canvas被挡住,或者被最小化,否则矩形不会被绘制。此时,我们从PaintEvent对象中获取gc对象,所以不需要释放它(没有使用new去创建就不需要去释放它)。

文字和颜色:SWT中两个重要的图形组件就是Font和Color。同样,也是由操作系统分配的,使用完之后也需要释放,和GC以及Display是一样的。可以直接在shell上进行绘制,而不一定必须使用Canvas。
shell.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
GC gc = e.gc;
Display d = e.widget.getDisplay();//从其他对象获取,不需要显示释放
Color color = new Color(d, 120, 42, 105);//手动创建Color对象,需要显式释放
gc.setForeground(color);
Font font = new Font(d, "Arial", 24, SWT.BOLD | SWT.ITALIC);//手动创建Font对象,需要显示释放
gc.setFont(font);
gc.drawString("Text", 20, 20);
color.dispose();
font.dispose();
}
});
shell.open();
图像:Image允许程序加载,绘制,显示图像。支持的图片包括BMP,ICO,JPEG,GIF,PNG。下面的简单的例子中,将从文件中加载图片,然后将其绘制在shell上。将display对象作为Device参数传递给Image构造方法,以及image的全路径名作为第二个参数。然后必须打开shell以便显示图片。如果颠倒这两个顺序,那么将会有一个延迟显示,因为加载图片需要一定的时间。
Image img = new Image(display, "EclipseBannerPic.jpg");
shell.open();
现在需要使用GC对象,来绘制图像,通过GC实例的drawImage方法。
GC gc = new GC(shell);
gc.drawImage(img, 0, 0);
结束之后,需要释放图像资源。因为图像属于重量级对象,并且要求系统资源。有些操作系统限制同时可以访问的图片的数量。同样,如果最小化或者拖拽窗口,可能导致图片被部分挡住或者不能显示。
JAR文件:如果要将程序和图片放到JAR文件中,那么必须修改程序以确保图片能够正常加载。因为此时图片在JAR文件中,而Image的构造器无法通过文件系统来直接访问。
InputStream is = getClass().getResourceAsStream("EclipseBannerPic.jpg");
Image img = new Image(display, is);
如果image位于JAR文件中的目录中,那么应该使getResourceAsStream(“images/EclipseBannerPic.jpg”)来加载图片。
Image(Device device, int width, int height)创建一个指定宽度和高度的空白图片。
Image(Device device, Rectangle bounds)同上,只是宽度和高度是由Rectangle对象指定的。
使用空白图片的目的用途是在屏幕外绘制图片,然后使用GC.drawImage()方法来绘制整个图片到屏幕,这样可以防止闪烁,因为直接在屏幕上绘制会很慢。
Image img = new Image(display, 50,50);
shell.open();
GC imgGC = new GC(img);
imgGC.drawLine(10, 20, 30, 40);
GC shellGC = new GC(shell);
shellGC.drawImage(img, 0, 0);
将图片应用于其他组件的方法是首先创建对象,然后调用组件的setImage方法。
Image(Device device, Image srcImage, int flag)用来创建重复的图片,通过flag来进行一些修改,flag可以是SWT.IMAGE_COPY, SWT.IMAGE_GRAY, and SWT.IMAGE_DISABLE。
Image original = new Image(display, "EclipseBannerPic.jpg");
Image copy = new Image(display, original, SWT.IMAGE_COPY);
Image gray = new Image(display, original, SWT.IMAGE_GRAY);
Image disable = new Image(display, original, SWT.IMAGE_DISABLE);
copy图像是原始的图像的拷贝,gray图像是原始图像的灰色版本,disable图像是disabled样式的原始图像。
b1.setImage(copy);
b2.setImage(gray);
b3.setImage(disable);
当为按钮设置图片之后,如果再次调用setText方法,那么文本会取代图片。标准的按钮不能同时显示文本和图像。还可以为菜单项,工具栏按钮,CoolBar上的按钮,树结构上的节点,Table中的TableItem等添加图像。
Splash屏幕:创建简单的闪烁屏幕。基本的技术就是使用SWT.NO_TRIM来创建Shell对象。这将产生一个没有窗口边框的shell,然后为其添加一个图片,来创建启动图片。然后让后台线程停止几秒钟,然后释放所有的资源,然后再运行实际的程序。
首先还是创建Display和Shell,只是Shell的样式设置为SWT.NO_TRIM。然后加载要splash的图片。可以通过Image来获取ImageData对象,来获取图片的实际的宽和高。
Display display = new Display();
Shell shell = new Shell(display, SWT.NO_TRIM);
Image image = new Image(display, "splash.jpg");
ImageData imdata = image.getImageData();
shell.setSize(imdata.width, imdata.height);
然后splash的时候将图片放在屏幕中央。
Rectangle r = display.getBounds();
int shellX = (r.width - imdata.width) / 2;
int shellY = (r.height - imdata.height) / 2;
shell.setLocation(shellX, shellY);
然后打开shell,并绘制图片。
shell.open();
GC gc = new GC(shell);
gc.drawImage(image, 0, 0);
然后让程序停止几秒种:
final int SLEEP_TIME = 4000;
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
}
然后释放所有的资源。
image.dispose();
shell.dispose();
display.dispose();
此时运行程序,会发现在屏幕中央显示图片,然后停留4秒,然后程序退出。本例只是简要介绍splash屏幕,实际的splash屏幕的作用是进行加载工作时显示进度条之类的功能。

MessageBox: MessageBox用于提示或者警告用户。MessageBox可以显示消息,图标,以及提供可选的按钮。
MessageBox messageBox = new MessageBox(shell, SWT.ICON_QUESTION |
SWT.YES | SWT.NO | SWT.CANCEL);
messageBox.setMessage("Do you like apples?");
可以选择的类型样式包括:ICON_ERROR,ICON_INFORMATION,ICON_QUESTION,ICON_WARNING,ICON_WORKING.可选的响应样式包括:OK,OK|CANCEL,YES|NO,YES|NO|CANCEL,RETRY|CANCEL,ABORT|RETRY|CANCEL。还可以通过setText为消息对话框提供标题。通过open方法打开消息对话框。
open方法返回一个整数,表示用户的响应:
response = messageBox.open();
switch (response) {
case SWT.YES:
System.out.println("Yes, the user likes apples.");
break;
case SWT.NO:
System.out.println("No, the user does not like apples.");
break;
case SWT.CANCEL:
System.out.println("The user cancelled.");
break;
}
ColorDialog:ColorDialog提供了颜色选择器。
ColorDialog colorDialog1 = new ColorDialog(shell);
colorDialog1.setText("ColorDialog Demo");
colorDialog1.setRGB(new RGB(255,0,0));
其中setRGB方法设置默认选中的颜色。
通过open方法显示对话框,open方法返回一个RGB对象,该对象为用户选择的颜色。
RGB selectedColor = colorDialog1.open();
DirectoryDialog:文件夹对话框用于浏览和选择文件夹。
DirectoryDialog directoryDialog = new DirectoryDialog(shell);
directoryDialog.setText("DirectoryDialog Demo");
directoryDialog.setFilterPath("C:/Program Files");
String selectedDirectory = directoryDialog.open();
DirectoryDialog和ColorDialog非常类似。
FileDialog:文件对话框用于选择文件。
String[] filterExtensions = { "*.txt", "*.doc", "*.*" };
FileDialog fileDialog = new FileDialog(shell, SWT.OPEN);//可选的样式有SAVE,OPEN,MULTI
fileDialog.setText("FileDialog Demo");
fileDialog.setFilterPath("C:/");//设置过滤的路径
fileDialog.setFilterExtensions(filterExtensions);//设置过滤的文件类型
String selectedFile = fileDialog.open();//返回选中的文件
FontDialog:字体选择对话框。
FontData defaultFontData = new FontData("Courier", 12, SWT.ITALIC);
FontDialog fontDialog = new FontDialog(shell, SWT.NONE);
fontDialog.setText("FontDialog Demo");
fontDialog.setRGB(new RGB(0, 0, 255));//设置文字颜色
FontData fontData = fontDialog.open();//获取选择的字体数据,字体名,样式(粗,斜...),颜色,字号等等。
PrintDialog:打印机对话框,允许用户选择打印机并进行打印操作。
Input对话框:Input对话框在SWT中并没有提供,但是可以手动创建,首先继承Dialog类,然后在面板上放置文本框和对应的按钮,添加open方法,方法返回输入的值以及选择的按钮(可以通过封装成一个Data类来完成)。
DnD(DragAndDrop):拖放功能允许用户快速的在应用程序之间传输数据。例如从桌面可以将文件拖放到”我的文档”中。首先必须导入所有与拖放有关的类:
import org.eclipse.swt.dnd.*;
* class org.eclipse.swt.dnd.Clipboard
* class org.eclipse.swt.dnd.DND
* class org.eclipse.swt.dnd.DragSourceAdapter (implements org.eclipse.swt.dnd.DragSourceListener)
o class org.eclipse.swt.dnd.DragSourceEffect
+ class org.eclipse.swt.dnd.TableDragSourceEffect
+ class org.eclipse.swt.dnd.TreeDragSourceEffect
* class org.eclipse.swt.dnd.DropTargetAdapter (implements org.eclipse.swt.dnd.DropTargetListener)
o class org.eclipse.swt.dnd.DropTargetEffect
+ class org.eclipse.swt.dnd.TableDropTargetEffect
+ class org.eclipse.swt.dnd.TreeDropTargetEffect
* class java.util.EventObject (implements java.io.Serializable)
o class org.eclipse.swt.internal.SWTEventObject
+ class org.eclipse.swt.events.TypedEvent
# class org.eclipse.swt.dnd.DragSourceEvent
# class org.eclipse.swt.dnd.DropTargetEvent
* class org.eclipse.swt.dnd.Transfer
o class org.eclipse.swt.dnd.ByteArrayTransfer
+ class org.eclipse.swt.dnd.FileTransfer
+ class org.eclipse.swt.dnd.HTMLTransfer
+ class org.eclipse.swt.dnd.ImageTransfer
+ class org.eclipse.swt.dnd.RTFTransfer
+ class org.eclipse.swt.dnd.TextTransfer
+ class org.eclipse.swt.dnd.URLTransfer
* class org.eclipse.swt.dnd.TransferData
* class org.eclipse.swt.widgets.Widget
o class org.eclipse.swt.dnd.DragSource
o class org.eclipse.swt.dnd.DropTarget
为了实现拖放功能,必须指定拖放源与拖放目标。下面的例子中使用标签作为拖放源
lblSource = new Label(shell, SWT.BORDER);
lblSource.setSize(200, 50);
lblSource.setLocation(50, 50);
lblSource.setText("This is the source label");
然后定义传输类型,可用的类型包括TextTransfer,RTFTransfer,FileTransfer,本例只用来传输纯文本,所以只适用TextTransfer。
Transfer[] types = new Transfer[] { TextTransfer.getInstance() };
接下来需要定义在拖放源上可以执行的操作:DROP_MOVE,DROP_COPY,DROP_LINK.
DROP_COPY: a copy of the data in the drag source is added to the drop target.
DROP_,MOVE:a copy of the data is added to the drop target and the original data is removed from the drag source.
DROP_LINK:the drop target makes a link to the data in the drag source.
int operations = DND.DROP_MOVE | DND.DROP_COPY;
然后创建DragSource对象:
DragSource source = new DragSource (lblSource, operations);
source.setTransfer(types);
接下来指定目标控件,这里也使用一个标签,然后创建DragTarget类,并指定操作和传输类型。
lblTarget = new Label(shell, SWT.BORDER);
lblTarget.setSize(200,50);
lblTarget.setLocation(50,150);
lblTarget.setText("This is the destination label");

DropTarget target = new DropTarget(lblTarget, operations);
target.setTransfer(types);
为了在用户开始拖拽文本时获取该事件,必须为source追加DragSourceListener,这里使用DragSourceAdapter:
source.addDragListener(new DragSourceAdapter() {
public void dragStart(DragSourceEvent event) {
if (lblSource.getText().length() == 0) {
event.doit = false;
}
};

public void dragSetData(DragSourceEvent event) {
if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
event.data = lblSource.getText();
}
}

public void dragFinished(DragSourceEvent event) {
if (event.detail == DND.DROP_MOVE)
lblSource.setText("");
}
});
dragStart方法在用户开始拖拽组件时被触发,应用程序可以决定是否执行拖放操作,本例中,如果lable的文字为空,则不执行该操作。dragSetData方法当用户将数据放在目标上时被触发,并且必须提供被放置的数据。这个方法必须支持由setTransfer指定的所有的数据传输类型。dragFinished方法在拖放完成或者放弃时执行。用于执行清理工作。
为了确保目标接受到拖放事件,也需要追加DropTargetListener。
target.addDropListener(new DropTargetAdapter() {
public void drop(DropTargetEvent event) {
if (event.data == null) {
event.detail = DND.DROP_NONE;
return;
}
lblTarget.setText((String) event.data);
}
});
Clipboard:Clipboard提供了从一个应用程序向另一个程序或者同一个程序中传输数据的机制。
参考资料:
SWT主页:http://www.eclipse.org/swt
SWT小例子:http://www.eclipse.org/swt/snippets/
SWT例子:http://www.eclipse.org/swt/examples.php
SWT文档:http://www.eclipse.org/swt/docs.php
Getting Started with Eclipse 2.1 and the SWT:http://www.cs.umanitoba.ca/~eclipse/
SWT Javadocs:http://help.eclipse.org/ganymede/index.jsp -> Platform Plug-in Developer Guide - > Reference -> API Reference -> org.eclipse.swt.*
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: