Picses' sky

Picses' sky
posts - 43, comments - 29, trackbacks - 0, articles - 24

[翻译]创建一个弹出通知部件

Posted on 2009-07-02 15:14 Matthew Chen 阅读(1244) 评论(1)  编辑  收藏 所属分类: Java SE

在本文中我将解释如何创建一个自定义的部件,它在屏幕右下角显示一个弹出通知对话框(Windows中通常是在工具栏上面) 。 以下是完成时它的样子:

Example Image

我们可以在组件上绘制一切来定制我们所需要的各种控制,但这篇文章的目的在于使用基本的SWT组件在一个普通的Shell中实现比典型SWT Shell更加美观的效果。

(注意,仅在Windows上进行过测试,在其它平台上可能有所不同) 。


Shell

我们想要一个shell停留在我们的程序的上方(但不是所有程序的上方),但不获取焦点、显示在你的任务管理器或是影响用户关注的对象。 我们也不使用"trim"来给Shell加边框而是绘制自定义的边框。我们所有的要求都可以通过SWT的flags参数方便的创建。我们可以如下创建Shell:



  1. _shell = new Shell(Display.getDefault().getActiveShell(), SWT.NO_FOCUS | SWT.NO_TRIM); 

由于我们的SWT组件在shell内部并且我们打算对shell本身使用渐变背景,所有的组件都必须是透明的。通过在shell上设置背景色模式为SWT.INHERIT_DEFAULT来实现。它告诉组建继承它们父组件的背景色。在创建shell之后我们简单调用:


  1. _shell.setBackgroundMode(SWT.INHERIT_DEFAULT); 

那么如何在shell上得到渐变的背景色呢?默认方式下是不支持的。你可以设置一个前景色和一个背景色但也就只能如此了。技巧是我们使用我们想要的颜色绘制一个图像来作为shell的背景。为了在合适的时间做到这一点,我们监听shell上的SWT.Resize事件,代码如下;


  1. _shell.addListener(SWT.Resize, new Listener() { 
  2.     @Override 
  3.     public void handleEvent(Event e) { 
  4.     try { 
  5.         // get the size of the drawing area 
  6.         Rectangle rect = _shell.getClientArea(); 
  7.         // create a new image with that size 
  8.         Image newImage = new Image(Display.getDefault(), Math.max(1, rect.width), rect.height); 
  9.         // create a GC object we can use to draw with 
  10.         GC gc = new GC(newImage); 
  11.  
  12.         // fill background 
  13.         gc.setForeground(_bgFgGradient); 
  14.         gc.setBackground(_bgBgGradient); 
  15.         gc.fillGradientRectangle(rect.x, rect.y, rect.width, rect.height, true); 
  16.  
  17.         // draw shell edge 
  18.         gc.setLineWidth(2); 
  19.         gc.setForeground(_borderColor); 
  20.         gc.drawRectangle(rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2); 
  21.         // remember to dipose the GC object! 
  22.         gc.dispose(); 
  23.  
  24.         // now set the background image on the shell 
  25.         _shell.setBackgroundImage(newImage); 
  26.  
  27.         // remember/dispose old used iamge 
  28.         if (_oldImage != null) { 
  29.         _oldImage.dispose(); 
  30.         } 
  31.         _oldImage = newImage; 
  32.     } 
  33.     catch (Exception err) { 
  34.         err.printStackTrace(); 
  35.     } 
  36.     } 
  37. }); 

内容

我们的shell由3个部分组成,图片在左上角(一个普通的CLabel ) 。 然后一个包含标题文字的标签(也是CLabel ) ,最后一个标签显示我们的信息(一个普通的Label) 。 我们最后使用一个Label而不是CLabel来支持比CLabel更佳的断行和多行效果。 您当然也可以使用几乎任何你想要的组建。 以下是用线框分割的每个标签:

tray_popup_example_lines

我们使用边缘间隔5px的GridLayout(除顶部)除此之外没有特别的效果创建,所以我就不在这里写出代码了(在底部供下载) 。

一些眼球效果-凋谢

在3.4的SWT中Shells支持alpha值设置,所以我们将以此来实现更美观的"呈现"和"消失",所有我们所需要做的就是在一个线程中循环增加/减少shell的alpha通道值来实现shell的淡入和淡出消失。我们必须在Display线程上来做这些操作,为此提供了一个runnable让Display对象以给定的时间间隔运行

在多线程的环境下记得始终检查shell是否已经被销毁了。当淡入显示完成后,我们希望shell显示一定时间然后消失掉,所以基本的流程链是

  • 创建shell
  • 淡入shell
  • 可的X秒
  • 淡出shell
  • 销毁shell

所有的这些定时器或多或少就如编码中的那样,所以我仅提供了一个例子其余的可以参考下载中的完整代码方面,我们需要解释一些全局的变量

  • FADE_IN_STEP是每次迭代中alpha值的增量。
  • FINAL_ALPHA是当shell保持可见时的alpha值。一定透明度的shell将提供更佳的效果,所以默认该值是225(255则为一个完全[不透明]的shell) 。
  • FADE_TIMER是alpha变化的时间间隔。当shell达到它的最大alpha值时调用startTimer()方法,这是一个线程,休眠若干秒,然后调用fadeOut()方法。

  1. private static void fadeIn(final Shell _shell) { 
  2.     Runnable run = new Runnable() { 
  3.  
  4.         @Override 
  5.         public void run() { 
  6.             try { 
  7.                 if (_shell == null || _shell.isDisposed()) { return; } 
  8.  
  9.                 int cur = _shell.getAlpha(); 
  10.                 cur += FADE_IN_STEP; 
  11.  
  12.                 if (cur > FINAL_ALPHA) { 
  13.                     _shell.setAlpha(FINAL_ALPHA); 
  14.                     startTimer(_shell); 
  15.                     return
  16.                 } 
  17.  
  18.                 _shell.setAlpha(cur); 
  19.                 Display.getDefault().timerExec(FADE_TIMER, this); 
  20.             } 
  21.             catch (Exception err) { 
  22.                 err.printStackTrace(); 
  23.             } 
  24.         } 
  25.  
  26.     }; 
  27.     Display.getDefault().timerExec(FADE_TIMER, run); 

堆叠的通知

最后我们要支持的,是堆叠通知。 假设我们的通知shell的整个生命周期是5秒,如果有额外的通知在第一个通知关闭之前到达呢?我们可以销毁第一个通知,并以后者取代,但更美观的方法是简单地将前者升高,让后者显示在前者的下方。效果如下(截屏时之前的shell开始淡出,所以它们有更高的透明度) :

tray_stacked

实现这一效果是相当简单的。 每次通知shell被打开,我们在静态的shell数组中保留一个引用。当它淡出(并销毁)后,从该列表中移除。因此,当一个新的shell到来后我们查看当前数组中已经存在的元素并对每一个旧的shell-heightOfNewNotificationShell 因此,旧的shell上移以腾出空间,但继续如前地完成它们的淡入/淡出周期。

进一步改善

当然一切都可以做得更加美观,也许你想要一个“ X ”关闭按钮,或不同颜色的文字,或圆角边框。 当前代码中并没有实现这些,但为你实现大多数功能避免问题

另外请注意,我目前使用Display.getDefault().getActiveShell()作为弹出窗口的夫shell。您可能想把它重构为一个永久性的shell以便在任何父shell被销毁或任何弹出窗被显示的时候都能使通知被销毁。

 

代码不是十全十美的,却可以作为构建的基础(如果你愿意的话) 。

下载代码

我已创建了一个基于Eclipse项目的代码,ImageCache / FontCache / ColorCache(它们的目的是为了缓存图片等系统资源)。 还有一个用来存放图片的jar。 如果你喜欢它们,可以找到更多: Gnome的颜色图标 。

请注意您可能需要调整您的CLASSPATH设置的项目,以对应自己的SWT jar所在。

运行Tester.java然后按下按钮启动通知。在前一个通知消失前再次按下随机图像将显示。

下载代码

结论

希望这可让您深入了解如何创建“自定义部件” (没有多少定制绘画)。 玩得开心!

Feedback

# re: [翻译]创建一个弹出通知部件  回复  更多评论   

2009-07-03 14:09 by 瑜伽馆
最近正想用,学习啦!

只有注册用户登录后才能发表评论。


网站导航: