第一个自定义SWT控件 – Advanced Navigator Bar

新项目已经开始,GUI上的改变还是一如既往的大,多,快!做GUI的真苦逼!

因为产品中有某种流程的概念,Boss需要一种能显示流程顺序且兼有Navigator功能的Bar。它在界面底部,用户可以用来做页面跳转。

Eclipse RCP使用SWT作为其图形库。在一顿乱Google之后,没有发现有现成的控件,所以只能自己做一个了。其实不是很想做,但作为一名GUI工程师,也不能总用标准控件吧。其实做控件并不难,以前在用wxWidgets,也做过几个控件,其实要点就几步,主要是费时调试。想想那会为了个控件调到凌晨4、5点,心里就觉得酸,:(。但这几个我费心做出的控件一直在产品中使用,算是一种安慰吧!

在Eclipse Corner Article里,找了篇文章(在Reference里),感觉和wxWidgets差不多。毕竟还是一个简单控件,试了一下,成功了, 同时感慨SWT有很多牛X的功能,远不是wxWidgets可以比的。

归纳几个要点。

控件重载

做自定义控件的第一步就是重载。SWT有两个比较适用的父类,

  • org.eclipse.swt.widgets.Canvas
  • org.eclipse.swt.widgets.Composite

Composite主要用来把其他控件compose在一起;Canvas则在给你提供一个画布,所有的显示行为都自己定义。这里显然Canvas更适合我。

计算大小

Parent控件或container在使用你的控件时,并不知道你的控件应该有多大。所以我们要提供Preferred Size。

在SWT中,你要重载compusiteSize(int wHint, int hHint, boolean changed). 这部分要根据控件中不同的内容来定,如图的大小,字符串的显示大小,它们怎么组织的。花点时间总是可以写出来的。

提一点,在这个函数中,你可能需要算字符串的长宽,所以你需要GC,所以你可以new一个然后用stringExtend计算大小。

重绘

有了大小了,下面就要告诉别人怎样把自己画出来。SWT里的办法是增加一个PaintListener.

在paintControl函数里,你就尽情地在GC上画吧。

事件响应

显示出来之后,和用户的交互也很重要。这里就要增加键盘和鼠标的事件。我的控件比较简单,只有鼠标事件。处理过程就是

  1. 响应鼠标事件
  2. 做点击测试
  3. 转换事件
  4. 找事件监听器处理

首先响应鼠标事件,

点击测试就是找出鼠标事件发生在哪个区域,里面会有一些Rectangle.contains()等类似的函数。有兴趣请在后面的Github上看看我的代码。

事件转换就是当你识别出事件后,把原来的鼠标事件做一个翻译包装,然后转发。比如在我的控件里,我要识别用户点在哪个Flow的节点上,所以我包装了一个节点变化的事件。

再做一个监听器给外部代码,某种简单的Observer的模式。

在控件里添加add/remove的接口,

其他要点

这几步就是最重要的。还有一些小的要点,

  • SWT中要注意把Color,Font等资源回收(dispose)
  • SWT可以用gc.setAntialias(SWT.ON)打开抗锯齿
  • 为了避免控件闪烁(flickering),特别是在频繁Resize里,可以在构造控件里加上SWT.DOUBLE_BUFFERED的style。

后两项都是wxWidgets无法比的,需要比较复杂的实现。

Github

代码还在准备中,很快上传。。。

References