在《打造专业外观-二》中,留下了3个未实现的功能:窗口标题和图标,边缘圆角,功能按钮。在本篇中将实现这些功能来完结打造专业外观-窗口部分的讲解。
一、窗口标题。
SWT窗口Shell有public void setText(String string),public void setImage(Image image) 方法用来设置标题和图标。但是现在窗口的样式已经是SWT.NO_TRIM,不再有标题栏了,因此标题只能自己“画”。在paintControl方法中添加如下代码:
else if (e.getSource() == northPanel) {
String text = getText();
if (text != null) {
gc.setForeground(titleColor);
gc.drawText(text, e.width / 2 - gc.stringExtent(text).x / 2,
e.height / 2 - gc.stringExtent(text).y / 2, true);
}
Image image = getImage();
if (text == null) {
text = "";
}
if (image != null) {
gc.drawImage(image, e.width / 2 - gc.stringExtent(text).x / 2
- image.getBounds().width - 10, e.height / 2
- image.getBounds().height / 2);
}
}
标题文字居中显示,图标居标题文字10像素。代码中“e.width”获取绘图环境上下文的长度,“gc.stringExtent(text).x”获得标题文字的长度,“true”表示绘制的文字不需要背景,如果是false,会看到有明显的灰色矩形作背景。绘制图标不难理解。当然通常的标题栏是九宫格的“上部”面板,所以要为northPanel添加绘制监听器。northPanel.addPaintListener(this);
二、边缘圆角
如果你不熟悉SWT的Region使用,请先研读http://www.eclipse.org/swt/snippets/中的“create a non-rectangular shell from a transparent image”程序。
该程序通过分析Image各个像素点的alpha值,来获取Region的填充。你可以通过本地图片实例化一个Image对象,支持透明的图片格式有PNG和GIF两种,美工都会知道这一点,本程序中用到的southwest.png、southeast.png、northeast.png、northwest.png均符合,以图片透明度来实现不规则窗体是常用的方法,这样做的好处是只要更换图片就可达到改变窗体形状。但是有些应用自身规定一种颜色为透明颜色,例如QQ,规定紫色为透明颜色,所以在它的实现中通过对图片逐个像素点分析,发现RGB是紫色就认为是透明。好,原理大致如此。下面来定义一个函数来完成次功能:
private Region getImageTransparenceRegion(Image image, int offsetX,
int offsetY) {
Region region = new Region();
final ImageData imageData = image.getImageData();
if (imageData.alphaData != null) {
Rectangle pixel = new Rectangle(0, 0, 1, 1);
for (int y = 0; y < imageData.height; y++) {
for (int x = 0; x < imageData.width; x++) {
if (imageData.getAlpha(x, y) != 255) {
pixel.x = imageData.x + x + offsetX;
pixel.y = imageData.y + y + offsetY;
region.add(pixel);
}
}
}
}
return region;
}
该方法参考了Snippet21(http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet219.java?view=co),方法返回给定图片透明部分构造的Region。然后在controlResized末尾添加如下代码:
Region oldRegion = getRegion();
if (oldRegion != null && !oldRegion.isDisposed()) {
oldRegion.dispose();
}
Region newRegion = new Region();
newRegion.add(0, 0, getSize().x, getSize().y);
newRegion.subtract(getImageTransparenceRegion(northwestImage, 0, 0));
newRegion.subtract(getImageTransparenceRegion(northeastImage,
getSize().x - northeastImage.getBounds().width, 0));
newRegion.subtract(getImageTransparenceRegion(southwestImage, 0,
getSize().y - southwestImage.getBounds().y));
newRegion.subtract(getImageTransparenceRegion(southeastImage,
getSize().x - southeastImage.getBounds().width, getSize().y
- southeastImage.getBounds().height));
setRegion(newRegion);
Shell实例通过setRegion(Region region)设置区域来实现不规则巨型窗体,但是前提是把样式设置成SWT.NO_TRIM。
由于窗体尺寸的变更相应的区域也要跟着调整,所以要把逻辑写在controlResized方法中,而且每次改变过后要释放Region资源并重新设置新的区域。上述在初始化Region对象后,“newRegion.add(0, 0, getSize().x, getSize().y);”方法将覆盖窗口整个区域,随后的subtract挖掉四个角落的透明部分。
三、功能按钮
出于时间比较紧,只添加关闭按钮,其他按钮如最小化、最大化原理相同。
通常按钮有四种状态,分别是:正常态、鼠标在上方、鼠标按下、被禁用。这4态对应4个图标。由于时间关系,只对需要注意的地方简单介绍。具体见完整代码。
无疑,4种状态切换要添加鼠标事件监听器。关闭按钮通过声明private Composite closeButton;来实现。具体位置本程序实现是右端与northeastPanel相邻,左边与northPanel相邻。在鼠标抬起时,要检查抬起点是否在该按钮上,如果是才执行关闭操作。见如下代码
if (e.x > 0 && e.x < closeButton.getSize().x && e.y > 0
&& e.y < closeButton.getSize().y){
// 执行关闭操作,否则鼠标在关闭按钮上方按下,但是不在其上松开,表明用户放弃关闭行为。
}
重写dispose方法如下:
@Override
public void dispose() {
try {
northwestImage.dispose();
northeastImage.dispose();
northImage.dispose();
southwestImage.dispose();
southeastImage.dispose();
southImage.dispose();
westImage.dispose();
eastImage.dispose();
closeImage.dispose();
closeOverImage.dispose();
color1.dispose();
color2.dispose();
titleColor.dispose();
} finally {
super.dispose();
}
}
首先是释放所有SWT本地资源,然后是super.dispose();释放窗口资源。
运行程序,界面效果如下
至此,打造专业外观-窗口部分的讲述就结束了,在这3篇幅中,主要讲述了九宫格的概念,九宫格法俗话说就是“贴图”,这个手法最常用也是最基础的,你会发现界面美观与否与图片有很大关系,同时桌面编程人员需要频繁与美工交互才能达到理想效果,如果没有合格的美工,但凭技术很难实现漂亮的外观,不过确实也存在只用多边形与曲线绘制组件的高手,swing的L&F就是这么实现的,但是贴图的好处是只要图片替换,外观也跟着替换,不用更改代码。
本程序只作为您设计的参考,欠缺还很多,并且没有对代码的健壮性、异常情况过多考虑,由于swt资源必须手工释放,如dispose方法中那样,其实那是最基本的,在实际环境下这么做还很有限,而且nullPoint异常也没有过多考虑。这都需要你自己去实现。
最终的完整程序这里下载