OSGi学习之Service Tutorial

0 评论  

Reference:http://www.knopflerfish.org/osgi_service_tutorial.html OSGi是Java里面的一个模块框架标准,Eclipse就是基于OSGi所开发,开源的OSGi实现大概包括Eclipse的Equinox,Apache的Felix,还有Knopflerfish,这些都是实现了OSGi R4标准的,其它的还有R3标准的,就不提了。 要做OSGI开发的话感觉还是Knopflerfish好点,Equinox本身位于Eclipse之中,如果不用Eclipse的话会比较恶心,Apache的那个例子太少,而且控制台界面也比较难用,我本来前段时间打算学Apache的Felix的,结果官方上面的文档太不全了,实在看不下去。Knopflerfish有一个Swing写的管理程序,文档虽然还是比较少,但起码比Felix要顺眼多了。 Knopflerfish的文档里面着重对Service这块进行了描述,我之前看Felix的时候都没看到过这个概念,当时就纳闷bundle直接怎么样去交互。搞了半天原来还有个Service的概念。。。 下面把官方的文档自己翻译一下,权当练习英文:)

Contents

  1. 什么是Service?
  2. Service Factory又是干啥的?
  3. Service都用来做什么用?
  4. Service怎么被别人访问?
  5. 释放Service?
  6. Service的最佳实践
  7. 白板模式

什么是Service

一个OSGi Service简单的说就是一个带有一堆属性(Properties)的Java 对象,跟普通对象的区别就在于它在OSGi框架里面进行了注册。任何的Java对象都开源注册成一个Service,但通常Service都是一些实现了某些接口可以供别的Bundle通过接口定义进行调用的对象。

这里推荐大家阅读OSGiR3 specification, chapter 4.10以及BundleContext的API文档以获得更详细的了解.

OSGiService的使用者毫无例外应该是一个OSGI的Bundle,也就是实现BundleActivator的类。

每个Bundle可以注册0个或多个Service,同样,它也可以使用0个或者多个Service。对Service的起限制作用的是内存的大小或者Java的安全策略。

无论是发布,注册,使用Service都可以通过Java的安全机制进行权限控制。

>以下代码展示了如何注册一个简单的Service。

Long      i     = new Long(20);
Hashtable props = new Hashtable();
props.put("description", "This an long value");
bc.registerService(Long.class.getName(), i, props);

注意:一个Service可以被注册成多个接口,这种情况下,注册为Service的对象就必须要实现所有的接口方法。

什么是Service Factory

Service Factory是一个特殊的类,它为每一个前来使用Service的bundle提供一个独立的进程。(大概就是每个Bundle都是用的Service的不同对象,互相之间不会有影响)

这样做的好处在于有时候不同的Bundle需要不同的Service配置,举例来说,日志Service需要能够打印出记录日志的是哪个Bundle,不然日志也会变得混乱而难以阅读。

Service Factory也需要注册,就像注册一个Service一样调用registerService方法,但有点不同的是ServiceFactory 是间接使用。(需要隐式调用factory.getService(..)?)

当Bundle使用Service的时候它不需要也不应该去关心到底这个Service是从ServiceFactory间接得来还是直接就是一个对象。

一个简单的ServiceFactory例子
class LongFactory implements ServiceFactory {
public Object getService(Bundle bundle, ServiceRegistration reg) {
// each bundle gets a Long with it's own id
return new Long(bundle.getBundleId());
}
void ungetService(Bundle bundle, ServiceRegistration reg, Object service) {
// nothing needed in this case
}
}

ServiceFactory factory = new LongFactory();
bc.registerService(Long.class.getName(), factory, new Hashtable());

注意:框架会对ServiceFactory生成的Service对象做缓存出来,这样就是说,对于每一个Bundle只会生成一个对应的Service对象。

Service都用来干啥?

Service是一个比较笼统的概念,不过它主要还是被设计为用在以下的场景中:

  • 将功能子模块从一个模块导出到另一个模块,实现子模块重用。
  • 从别个模块导入一些功能函数子模块
  • 通过Service在别的模块里面注册监听器
  • 把诸如UPnp设备或者其它硬件设备暴露给其它的OSGIBundle,See the Device and UPnP APIs
  • 通过UPnP或者SOAP协议把java和其它平台语言结合起来。
  • 通过 Configuration Manager实现对Bundle的配置管理

总的来说,Service是Bundle之间用来通信的首选方法

Service怎样被访问到

Service通常是通过Service References来引用一个唯一的Service对象。
为了访问Service,以下两个步骤是必须的:
  1. 得到一个 ServiceReference
  2. BundleContext.getService()从Service Reference里面得到相应的Service对象。
而ServiceReference则是通过下列步骤得到:
  1. 直接调用BundleContext.getService() 这样会返回一个对象或者返回Null。
  2. 直接调用BundleContext.getServices() 返回完全匹配的对象。(1,2有点晕了)
  3. ServiceListener 的方法回调中得到
  4. 使用工具类 ServiceTracker

上述四种方式除了第一种,其它的都可以通过指定一个LDAP filters 来对Service进行精确定位,这样经过过滤之后就可能有0个或多个匹配的Service对象。

典型的Filter包括一个类名和一组属性值。下面的例子匹配一个带有Port属性为80的HTTP Service。

LDAP Filter字符串
(&(objectclass=org.osgi.service.http.HttpService)(port=80))

一旦ServiceReference就绪之后,Service就可以通过强制转型得到

 HttpService http = (HttpService)bc.getService(sr);

这样,Service对象可以像普通对象一样被访问,实际上,Service对象也完全是一个普通的Java对象,更具体的说,这个对象就是Bundle在注册Service的时候所创建的那个对象。

释放Service

一旦Service对象不再使用,使用者需要调用 BundleContext.ungetService() 方法来释放资源.

 bc.ungetService(sr);

另一方面,当使用者所在的Bundle停止的时候所有的相关联的Service都会自动被释放,所以,在BundleStop方法这里无需再添加Service对象的清理过程。

注意:Service对象只有在它真正不被使用的时候才可以释放。有些Service可能会保持一些通用的状态信息,释放Service对象的同时这些状态信息也可能同时被释放,这个要视乎Service本身的行为。前面提到的HttpService就会移除所有的Servlet和资源一旦有一个使用者释放了这个HTTP Service。

当Service释放的时候,相应的ServiceListener会收到相应的ServiceEvent.UNREGISTERING事件通知。

当Service注销掉以后,再调用GetService反复只会得到一个Null对象。

注意:很常见的一种情况就是使用者通过变量保存了一个Service对象,在Service注销过后,这个变量所指向的Service将不能继续使用,这个时候应该将这个变量置为Null以便GC能够回收内存。

最佳实践

Service的状态极不稳定,所以任何时候都有可能会变得不可用。

最佳实践:

  • 总是记住Service在调用的时候就像RMI,总是有可能会出现异常,所以程序在调用的时候应该记得在处理异常,也并不是说每次调用都需要TryCatch,可以在一个比较高的层次统一处理这些异常。
  • 使用白板模式
  • 尽可能的把代码构造成一个Service给别的Bundle使用而不是从别的Bundle获取Service
  • 使用侦听器 ServiceListenerServiceTracker p提供了不同Level的获取Service的方法。
  • 使用声明式的ServiceBinder ServiceBinder 通过XML对Service的依赖关系进行描述。
考虑一下下面这种普遍的不好的写法:
ServiceReference sr  =  bc.getServiceReference(HttpService.class.getName());
HttpService http     = (HttpService)bc.getService(sr);
http.registerServlet(....)
这里每一行都有可能会Fail
  1. 如果HTTpService没有注册,ServiceReference 可能会为Null,这样第二行就会有NullPointerException。
  2. HTTP Service可能会因为没有授权或者说刚好HTTP Service在第一行代码跟第二行代码直接被注销,这样都会造成第三行的地方出现NullPointerException。
  3. HTTPService随时可能会变得不可用,所以第三行也极有可能出现IllegalStateException

上述的异常情形通过条件判断可用简单的避免:

ServiceReference sr  =  bc.getServiceReference(HttpService.class.getName());
if(sr != null) {
  HttpService http = (HttpService)bc.getService(sr);
  if(http != null) {
     http.registerServlet(....)
 }
}

不过这种方式很快就显得很笨重,而且多个IF,ELSE也会让代码变得难以捉摸。

使用ServiceListener是个不错的解决方案:

ServiceListener sl = new ServiceListener() {
public void ServiceChanged(ServiceEvent ev) {
ServiceReference sr = ev.getServiceReference();
switch(ev.getType()) {
case ServiceEvent.REGISTERED:
         {
           HttpService http = (HttpService)bc.getService(sr);
            http.registerServlet(...);
         }
         break;
       default:
         break;
     }
 }
};

String filter = "(objectclass=" + HttpService.class.getName() + ")";
try {
 bc.addServiceListener(sl, filter);
} catch (InvalidSyntaxException e) {
 e.printStackTrace();
}

上述代码中唯一可能出现异常的在第8行,不过这个异常通过是又框架在事件分发Code中处理的,所以如果没有特殊的要求,上述代码就已经足够了。

另外还有一个问题,如果所有的HTTPService都已经被注册了,那么上述的Listener可能会因为HttpService重启而Fail。手动去构造ServiceEvent然后调用Listener可以解决这个问题:

Construct ServiceEvents - contd. from above
try {
  bc.addServiceListener(sl, filter);
  ServiceReference[] srl = bc.getServiceReferences(null, filter);
  for(int i = 0; srl != null && i InvalidSyntaxException e) {
  e.printStackTrace();
}

使用ServiceListener的话,上述的代码已经达到了25行之多,使用ServiceTracker会更加简洁:

ServiceTracker example
ServiceTracker logTracker = new ServiceTracker(bc,LogService.class.getName(), null);
logTracker.open();
((LogService)logTracker.getService()).doLog(...);

ServiceTracker负责保证所有的Service都是可用的,如果某个Service不再可用则返回Null。这样的话就只需要再关系RuntimeException了。

下面的代码对ServiceTracker进行了封装,这样调用的时候就更加简单了:

ServiceTracker logTracker;

void init() {
  logTracker = new ServiceTracker(bc, LogService.class.getName(), null);
}

LogService getLog() {
  return (LogService)logTracker.getService();
}

void test() {
  getLog().doLog(...);
}

白板模式

"Don't call getService(), call registerService() instead!" 不要试图调用getService()而是要用RegisterService()来代替。

考虑以下HTTPService 这个例子。调用者通过需要把它们的Servlet加到WebServer当中,这就需要一堆的查找,使用Service的代码。

另外,HTTPService必须提供额外的方法供增加和移除Servlets的时候调用,而且必须维护一个Servlet的列表。这样会增加API和代码本身的复杂性。

把Servlets注册为Service,让HTTPServer来使用这些Service不失为一种更好的方法。

Servlet client
class MyServlet extends HttpServlet {
 ...
}

HttpServlet servlet = new MyServlet();
Hashtable   props   = new Hashtable();
props.put("alias",  "/servlets/foo"); // desired http alias
ServiceRegistration reg =   bc.registerService(HttpServlet.class.getName(), servlet, props);

客户端只需要把HTTPServlet注册为Service即可。

reg.unregister();
下面的代码展示了对HTTP Service的包装,完整的代码见Http Console例子
HttpService wrapper
void open() {
httpTracker = new ServiceTracker(bc, HttpService.class.getName(), null);
httpTracker.open();

ServiceListener sl = new ServiceListener() {
public void serviceChanged(ServiceEvent ev) {
ServiceReference sr = ev.getServiceReference();
switch(ev.getType()) {
case ServiceEvent.REGISTERED:
{
   registerServlet(sr);
}
break;
case ServiceEvent.UNREGISTERING:
{
   unregisterServlet(sr);
}
break;
}
}
};

String filter = "(objectclass=" + HttpServlet.class.getName() + ")";
try {
bc.addServiceListener(sl, filter);
ServiceReference[] srl = bc.getServiceReferences(null, filter);
for(int i = 0; srl != null && i < servlet =" (HttpServlet)bc.getService(sr);" alias        =" (String)sr.getProperty(" httplist =" httpTracker.getServices();" i =" 0;" http =" (HttpService)httplist[i];" props =" new" alias        =" (String)sr.getProperty(" httplist =" httpTracker.getServices();" i =" 0;" http =" (HttpService)httplist[i];">

Java 嵌入浏览器-DJ NativeSwing

1 评论  

Java里面的嵌入浏览器一直比较麻烦,不像C#,VB想调用IE的时候只需要一句话就搞定了,不过现在许多应用都需要在UI里面嵌入一个浏览器,就像Qq,MSN之类,而且如果DesktopUi跟嵌入浏览器能进行数据传递,相互调用的话那就更好了。 以前在Swing里面一直知道的就是JDIC了,JDIC是通过JNI包装调用IE或者FireFox,虽然调用方式比较丑陋,不过基本的还是实现了,起码在Swing里面也能调 了,不过Swing里面只能简单的进行到浏览器的前进,后退,加载,刷新,停止操作,对某些特殊的想法就无能为力了。 今天无意中看到了DJ Native的项目,其实这个项目好像很久之前也看到过,看过Demo,当时没细看,只觉得跟JDIC也差不多,今天才发现,原来DJ native要强大很多。 DJ Native解决了一些JDIC的问题,比如说 轻量级的Swing组件跟它的重量级的组件的绘制问题,Z-order问题。还有Swing的model窗口无法block重量级组件的问题,已经重量级组件跟Swing线程交互的问题。 其实DJ Native底层是用基于SWT实现,众所周知,SWT是IBM搞的对本机API的包装,而且SWT经历过比JDIC更多的检验,比如说Eclipse之类,所以就这一点DJ Native也应该比JDIC有优势。 DJNative里面包含了五个组件和一个文件关联工具,组件包括JWebBrowser,JFlashPlayer,JVLCPlayer,JHTMLEditor,JWMediaPlayer(win32). 分别介绍:

  • JWebBrowser:
细心的人应该能看出这个是对SWT里面的浏览器做了一个封装,使之适应到Swing的环境下面,而SWT又是对本机浏览器的封装,通过JNI,不过这里面有两个个很大的亮点就是1.JWebBrowser支持从Swing调用JavaScript代码段动态的改变页面的内容。 2.JWebBrowser支持从页面上发送参数到Swing端。 这两个特性太酷了,这样就可以实现HTML页面跟Swing的相互调用交互。 JWebBrowser
  • JFlashPlayer:
JFlashPlayer跟JWebBrowser一样,是对FlashPlayer的一个封装,之所以独立的对FlashPlayer进行封装,这里有一个主要的目的就是能够对Flash进行交互,跟JWebBrowser一样,能够从Swing调用FlashPlayer里面的函数也能从FlashPlayer发送参数到Swing端。这个也很酷,不过我不会Flash,所以也就算了。 JFlashPlayer
  • JVLCPlayer:
JVLCPlayer这个是封装了一个VLC的播放器,之所以封装一个VLC的播放器我想应该是出于跨平台的考虑吧,IE里面其实本身也有Embed的播放器的。 JVLCPlayer
  • JHTMLEditor:
JHTMLEditor是封装的一个FCKEditor,其实我之前也一直在想既然Swing没有很好的HTML所见即所得的编辑器,为什么不用JDIC嵌入一个浏览器,然后再调用FCKEditor之类,不过这样做有个很大的问题就是如何跟浏览器交互的问题,你可以通过JDIC得到当前浏览器的整个内容,但是这样做还得遍历整个浏览器的文档去找到用户在FCKEditor里面输入了什么。
  • JWMediaPlayer(w32):
这个是针对WindowsMediaPlayer的一个封装。 更多的去作者的文章里面看吧:http://java.dzone.com/news/dj-nativeswing-reloaded-jwebbr

25 Rounded Corners Techniques with CSS,25种不同的CSS圆角边框技术

0 评论  

【转】好久不写HTML了,记得以前写HTML的时候,对于圆角边框一直很耿耿于怀,那个时候觉得圆角边框实现起来挺难的,尤其是那种带阴影效果的圆角边框,很好看,但似乎很难实现,呵呵,今天又想起这个事情,搜索到一篇文章,列举了25种用CSS实现的圆角边框,挺唬人的。现整理如下(绿色部分是我的注释):

Rounded corners is one of the most popular and frequently requested CSS techniques even the father of internet Google also launch the rounded corners style markup with her Google Adsense and let users to custom their ads recently. Actually, there are a lot of methods and techniques to create rounded corners with Cascading Stylesheets. Some are quite simple just need pure CSS, and a part of them need 2 to 4 background corner images and Javascript. So i select some quality and usable rounded corners with CSS techniques for you to have the best choices.

Techniques

  • ThrashBox:

ThrashBox - create rounded-corner boxes with visual flare and the absolute minimal amount of semantically correct markup. http://www.vertexwerks.com/tests/sidebox/

(ThrashBox效果挺不错,Border很有立体感,不过因为要实现对较大尺寸的Border也支持,所以图片的尺寸也比较大)。

  • EvenMore:

Even More Rounded Corners With CSS - nice technique with fluid rounded corner dialogs and support for borders, alpha transparency throughout, gradients andpatterns.

Even More Rounded Corners With CSS

(Even More的这个在Firefox里面效果很炫,不过在IE6里面边角有白边,而且两者的速度都有问题,会有闪烁的感觉)

  • DomCorner:

DomCorners - a very simple technique for getting rounded corners. DomCorners

(DomCorner比较简洁,不过效果一般,且需要额外的JS文件。)

  • virtuelvis.com Rounded corners

virtuelvis.com Rounded corners in CSS - allow you to retrofit this to existing designs without altering any markup. Rounded corners in CSS

Virtuelvis在IE里面不行,这个最郁闷了。

  • TCCB

Transparent custom corners and borders version 2 - a technique for creating custom corners and borders with optional alpha transparency. Transparent custom corners and borders version 2

这个Corner在IE里面跟在FireFox里面效果差距有点大,在IE里没有阴影效果了,看来还是FireFox好,哈哈。

  • CSS Teaser Box with rounded corners

CSS Teaser Box with rounded corners - by Roger Johansson, the same author of Transparent custom corners and borders version 2. CSS Teaser Box

  • News List

News List - was designed to display links to recent news. news list

  • CSS Liquid Round Corners

CSS Liquid Round Corners - a re-usable rounded box, note that it needs total 6 images for wrap the corners. CSS Liquid Round Corners

  • Anti-aliased Nifty Corners

Anti-aliased Nifty Corners - based on Nifty Corners and modified by Steven Wittens. Anti-aliased Nifty Corners

  • Simple Box by tedd

Simple Box by tedd - another simple rounded corners. Simple Box by tedd

  • CSS and round corners

CSS and round corners making accessible menu tabs - decent rounded corners style menu tabs technique. CSS and round corners Making accessible menu tabs

  • CSS and round corners borders with curves

CSS and round corners borders with curves - make a rounded corners borders with curves. CSS and round corners Borders with curves

  • Airtight Corners

Airtight Corners - produce a box with rounded corners using only one image, and off-setting that image for each corner. Airtight Corners

  • Mountaintop Corners

Mountaintop Corners - easier way for creating decent rounded corners. Mountaintop Corners

  • Editsite Rounded Corners

Editsite Rounded Corners - need a javascript to create the corners. http://www.editsite.net/blog/rounded_corners.html

  • Create a rounded block or design with CSS and XHTML - easily create a rounded block
Create a rounded block or design with CSS and XHTML
  • Resizable box with freely stylable corners and surface - resizable rounded corners box.
Resizable box with freely stylable corners and surface

  • Smart Round Corners - a practical solution to uses small images for markup the corners.

    Smart Round Corners

  • Lean and Clean CSS boxes - need 2 images to wrap the header and box.

http://www.tjkdesign.com/articles/roundbox.asp

Broader Border Corners - a quick and easy recipe for turning those single-pixel borders. Broader Border Corners

Snazzy Borders - based on Nifty Corners By Alessandro Fulciniti Snazzy Borders

Rounded corners in CSS by Adam Kalsey - requires 4 corners images. Rounded corners in CSS by Adam Kalsey

curvyCorners - a free JavaScript program that will create on-the-fly rounded corners for any HTML DIV element, that look as good as any graphically created corners. curvyCorners

Nifty Corners - a solution based on CSS and Javascript to get rounded corners. Nifty Corners

quinncrowley.com - based upon a combination of pixy and Kalsey http://www.quinncrowley.com/rounded.htm

Rounded Corners Generators

Online rounded corners generators, Rocks! http://www.roundedcornr.com/ - the herald of rounded corners generator tool. http://www.roundedcornr.com/

http://www.spiffycorners.com/ - simple way to generate the CSS and HTML you need to create anti-aliased corners without using images or Javascript. http://www.spiffycorners.com/

http://tools.sitepoint.com/spanky/ - an experimental technique for using only CSS to produce ’round-cornered content boxes’ with semantically pure markup. http://tools.sitepoint.com/spanky/

http://spiffybox.com/ - another project by the owner of Spiffy Corners. http://spiffybox.com/

太多了,哎,还是不整理了,就这样吧,下次用到了再挑个出来

Swing屏幕截图工具 Swing Screen Capture 之二,实现QQ屏幕截图

2 评论  

前几天的截图工具其实跟QQ的原理不一样,QQ的截图给人感觉是在按下截图按钮之后界面会冻结,界面怎么可能冻结呢?这里一样用了一个全屏的程序,并把按下按钮之前的屏幕截图,作为全屏程序的背景,这样就给人感觉屏幕以冻结。可能你会问,那这个时候如果我按ALT+TAB切换呢,呵呵,QQ把这个程序作为AlwaysOnTop的了,这样就算你切换完了,还是全屏显示这个冻结的画面。 上次做的感觉原理跟QQ的各有千秋吧,QQ这个就像相机,按下快门就已经截图了,只是后面再在截的图上面做裁剪,而上次的那个是动态的,你先取好景,支好三脚架,然后静待美景的出现,再按下快门。 这里我也修改了一下上次的代码,做了个Java版的QQ截图工具,开始截图之前会先通过Robot截取整个屏幕,然后再通过CropImageFilter对图片做裁剪,裁剪代码如下:

     Image captureImage = null;
     ImageFilter cropFilter;
     cropFilter = new CropImageFilter(pn.x,pn.y,pn.width,pn.height);//四个参数分别为图像起点坐标和宽高,即CropImageFilter(int x,int y,int width,int height),详细情况请参考API

     captureImage = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(), cropFilter));
网上搜索了一下java 图片裁剪,结果少的可怜,看来这个类被人并不常用啊。不过换成从BufferedImage裁剪到Image以后确出了问题,Image不能直接调用ImageIO输出图片了,后面又折腾了半天,把Image又转换会BufferedImage,再保存,晕了,似乎也没什么好的办法了,认了吧。 BufferedImage转Image代码:
      BufferedImage bufferedImage = new BufferedImage(captureImage.getWidth(null), captureImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
     Graphics2D g = bufferedImage.createGraphics();
     g.drawImage(captureImage, null, null);

  • 主屏幕截图:
  • 截图结果:

A Thumbnail Preview Tabbed Pane

0 评论  

【转】 From:http://weblogs.java.net/blog/aberrant/archive/2008/06/a_thumbnail_pre_1.html

Posted by aberrant on June 17, 2008 at 04:07 AM

Lately I've been spending my spare time contributing code samples to the The Java Tutorial Community Portal. My hope is that one or more of these examples will be interesting enough to be included in the official tutorial. My latest addition is an example on how to override tool tip generation for a particular component. This example is a tabbed pane that shows a preview of a tab as a tooltip.

In this picture the mouse was hovering over the "images" tab.

There are techniques for installing custom universal tool tip providers. In this case I only wanted to change the behaviour for one particular component. To accomplish this I overrode the createToolTip() method of JTabbedPane with the following:

/**
* overide createToolTip() to return a JThumbnailToolTip
*/
@Override
public JToolTip createToolTip() {
Point loc = getMousePosition();
int index = indexAtLocation(loc.x, loc.y);

if (index != -1) {
Component comp = getComponentAt(index);

BufferedImage image = ImageFactory.toImage(comp);

JToolTip tip = new JImageToolTip(image, 0.5);

return tip;
} else {
return super.createToolTip();
}
}

This method returns an instance of JImageToolTip which displays an image of the hidden component instead of the tooltip text. The image of the component was generated by the toImage() method of my ImageFactory class.

/**
* Generates a buffered Image of the specified component.
*
* @param componet
* @return image 'snapshot' of the component and it's state at the time this
*         method was called.
*/
public static BufferedImage toImage(Component componet) {
BufferedImage image = new BufferedImage(componet.getWidth(), componet
.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics graphics = image.getGraphics();
graphics.setColor(componet.getBackground());
graphics.fillRect(0, 0, componet.getWidth(), componet.getHeight());
componet.paint(graphics);
graphics.dispose();

return image;
}

The JImageToolTipThis also class was used to create a label that displays a thumbnail of an image and provides the full size image as a tooltip.

I've made the full source code available. Comments on this or any other code sample are welcomed and encouraged.

Source Code: ThumbnailTooltipDemo-src.zip

记得以前在Let's Swing Java 的博客上也看到过一篇类似的文章,不过当时感觉他的实现方式似乎比较复杂也就没细看,aberrant的实现方式还是比较简洁的,通过短短的组件的paint方法把组件绘制到一个BufferImage中,不错。

Swing屏幕截图工具 Swing Screen Capture

0 评论  

前两天装Spark的时候发现里面有一个截图工具很炫,Spark是用Swing写的,那这个截图的Function应该也是用Swing来写的,就在想实现的原理,网上搜索了一下,不过多半是讲怎么样截取整个屏幕,但如果要对屏幕上某个区域截图的话似乎是没人提到的。最大的难点应该在于如何在整个屏幕上显示一个可以拖拽的透明矩形框,这个问题我以前也想过,不过一直没想到好的解决方案,其实现在想想关键在于思维局限性,只是想到在屏幕上面绘制一个单纯的透明矩形框,其实完全可以绘制一个大的透明的Cover将整个屏幕遮住,然后再在这个Cover上绘制矩形框就OK了。原理就这么简单了,呵呵,上我的截图:

  • 选取屏幕某块区域:
黑色铅笔区域就是截图工具的选择区域。
  • 截图完成
还有点不足的是,因为用到了窗体透明,所以本程序基于JDK 6 update 10Beta,JDK 6 update 10正式发布估计也还有好几个月吧,这个是局限。 不过通过屏幕截图绘制背景图的方式也可以实现透明,但比起的Sun官方实现,还是略显笨拙。 完整源代码下载。

Swing: Context Menu for TextComponents 文本控件右键菜单

0 评论  

Java编写的GUI程序里面,AWT,SWT,QT Jambi都是基于C++ Dll绘制界面,也就是所谓的重量级界面,而Swing是通过Java2D绘制出来的,完全基于java实现,是轻量级界面。Java的这个轻量级界面有对应于每个操作系统平台的Look and Feel,可以把程序装饰得跟本机程序一样。拿Windows里面的Look and Feel来说,几近以假乱真的程度,不过我还是可以通过一点来很容易的区分Java程序,那就是文本框对右键是没有任何反应的,普通的文本框,右键的时候都会有一个菜单,Cut,Copy,Paste,Select All,而Java的文本框?Nothing。这个缺陷其实不算大问题,Ctrl+C,Ctrl+v。。。就可以实现上面的这些功能,不过,想当初我学电脑的时候,也有很长很长一段时间不知道CTRL+C这些快捷键的,所以怎么说没有右键菜单都让人会觉得Swing在UI这块还是不够Professional,呵呵。 还记得去年实习,在公司做Swing的时候,就有这个想法,那个时候也花了大半天的时间去搜索现成的东东,不过没有找到,其实现在想想这个东西还是跟搜索的关键字有关,从技术的角度来讲,用中文搜跟用英文搜差别太大了,我今天又突然想起这个问题,用英文搜索了一下,结果第一页就找到答案了,呵呵,看来boldtech没白来,起码英文用得多一点了,对学习技术有帮助。 我首先搜索到的一篇文章,写文章的人也是因为对这个问题诟病很久了,它在文章里面提到要实现其实也不难,两种理所当然的方式,一是扩展这些文本组件,二是添加全局的MouseListener,实现Popup,不过这两种方式都被他否定了,因为这两种方式的代码量都比较多,前者需要扩展多种文本组件,TextField,TextArea之类,而且需要将之前的TextField,TextArea做一遍替换,后者则是针对每个Frame都要添加一遍Listener。然后作者提到了一种方案,通过自定义EventQueue来实现,主要的代码如下:

// @author Santhosh Kumar T - santhosh@in.fiorano.com 
public class MyEventQueue extends EventQueue{
protected void dispatchEvent(AWTEvent event){
super.dispatchEvent(event);

// interested only in mouseevents 
if(!(event instanceof MouseEvent))
return;

MouseEvent me = (MouseEvent)event;

// interested only in popuptriggers 
if(!me.isPopupTrigger())
return;

// me.getComponent(...) retunrs the heavy weight component on which event occured 
Component comp = SwingUtilities.getDeepestComponentAt(me.getComponent(), me.getX(), me.getY());

// interested only in textcomponents 
if(!(comp instanceof JTextComponent))
return;

// no popup shown by user code 
if(MenuSelectionManager.defaultManager().getSelectedPath().length>0)
return;

// create popup menu and show 
JTextComponent tc = (JTextComponent)comp;
JPopupMenu menu = new JPopupMenu();
menu.add(new CutAction(tc));
menu.add(new CopyAction(tc));
menu.add(new PasteAction(tc));
menu.add(new DeleteAction(tc));
menu.addSeparator();
menu.add(new SelectAllAction(tc));

Point pt = SwingUtilities.convertPoint(me.getComponent(), me.getPoint(), tc);
menu.show(tc, pt.x, pt.y);
}
}
很简单?的确,只是在MouseEvent里面对Event进行过滤,对右键菜单,并且是来自文本组件的右键菜单添加Popup菜单,
这种方案的确比较简单,最终只需要一行代码,
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new MyEventQueue()); 将这个EventQueue加到系统的EventQueue
中就Ok了,不过这个贴发出来以后就有很多反对的声音,主要是这种对全局右键事件的监听可能会打破原有的事件监听体系。
所以这个方案也只是 看上去很美,不过后面有人提到Swinglab的SwingX项目里面通过在look And Feel 里面添加 auxiliary LF
来实现,刚好我在IPSeeker里面 用到了SwingX项目,结果通过一行代码也实现了右键菜单,
UIManager.addAuxiliaryLookAndFeel(new ContextMenuAuxLF());
其中ContextMenuAuxLF位于SwingX中,org.jdesktop.swingx.plaf.ContextMenuAuxLF,不过这个文件的代码我没怎么看懂,大概就是
通过在重新TextUI,在其中加入每个textComponent对应的Action所生成的Popup。代码都不多,看似很简洁,很美,
IPSeeker中右键菜单截图:
  • 空白文本框中的右键菜单
  • 选中文字后右键菜单
  • TextArea中的右键菜单

SwingX 实现分析:
SwingX是开源的,这点很不错,直接看源代码就可以知道是怎么实现的了,我感觉编程不是一个技术活,经过一段时间的
培训,人人都可以编程,关键要是编出很好看的代码,那才叫牛逼,就像写文章,每个人都会写,但只有少数人能够成为
作家。扯远了,前面也提到SwingX的实现方式主要是通过
UIManager.addAuxiliaryLookAndFeel(new ContextMenuAuxLF());给当前的UIManager添加一个辅助的LookAndFeel,这个
特性很重要,很多时候重新一个LookAndFeel所需要的工作量是相当巨大而且可能是没必要的,这个时候通过调整部分UI,
作为一个辅助的LookAndFeel来添加就显得尤为重要,说白了这个辅助的LookAndFeel会覆盖当前LookAndFeel当中已有的
部分,而辅助的LookAndFeel没有实现的那些部分让又原有的LookAndFeel负责。
  • 下面介绍下ContextMenuAuxLF(注释部分用绿色标出,下同):
/*
* $Id: ContextMenuAuxLF.java,v 1.5 2006/03/30 10:19:12 kleopatra Exp $
*
* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
package org.jdesktop.swingx.plaf;

import javax.swing.LookAndFeel;
import javax.swing.UIDefaults;

/**
* Support for context dependent popup menus.
*
* It's meant to be used as a auxiliary LF on top of main LF:
*
*  
*  
*  UIManager.addAuxiliaryLookAndFeel(new ContextMenuAuxLF());
*  
*  
* * There are core-issues involved, which might or might not * impair its usefulness, for details please see a thread in * the SwingLabs forum:

* * * Experimental: default context menus for textcomponents/scrollbars * * * * @author Jeanette Winzenburg */ public class ContextMenuAuxLF extends LookAndFeel { private UIDefaults myDefaults; public String getName() { return "ContextMenuAuxLF"; } public String getID() { return getName(); } public String getDescription() { return "Auxiliary LF to Support Context Dependent Popups"; } public boolean isNativeLookAndFeel() { return false; } public boolean isSupportedLookAndFeel() { return true; } public UIDefaults getDefaults() { if (myDefaults == null) { initDefaults(); } return myDefaults; } private void initDefaults() { myDefaults = new MyUIDefaults(); Object[] mydefaults = { "TextFieldUI", "org.jdesktop.swingx.plaf.ContextMenuAuxTextUI", "EditorPaneUI", "org.jdesktop.swingx.plaf.ContextMenuAuxTextUI", "PasswordFieldUI", "org.jdesktop.swingx.plaf.ContextMenuAuxTextUI", "TextAreaUI", "org.jdesktop.swingx.plaf.ContextMenuAuxTextUI", "TextPaneUI", "org.jdesktop.swingx.plaf.ContextMenuAuxTextUI", "ScrollBarUI", "org.jdesktop.swingx.plaf.ContextMenuAuxScrollBarUI", }; myDefaults.putDefaults(mydefaults); /*关键在于这里,UIDefaults其实是一个HashTable,通过观察你也许就会发现,这里用来初始化UIDefaults的 是一些键值对,键是UI,Name是这个UI对应的实现。这里把TextField,EditorPane,PasswordField,TextAreaUI都初始化 "org.jdesktop.swingx.plaf.ContextMenuAuxTextUI"实现 */ } /** * UIDefaults without error msg. * */ private static class MyUIDefaults extends UIDefaults { /** * Overridden to do nothing. * There will be many errors because this is incomplete as * of component types by design * */ @Override protected void getUIError(String msg) { } } }

  • ContextMenuAuxLF引用到ContextMenuAuxTextUI
/*
* $Id: ContextMenuAuxTextUI.java,v 1.5 2005/10/24 13:20:45 kleopatra Exp $
*
* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
package org.jdesktop.swingx.plaf;

import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseListener;

import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.TextUI;
import javax.swing.text.BadLocationException;
import javax.swing.text.EditorKit;
import javax.swing.text.JTextComponent;
import javax.swing.text.View;
import javax.swing.text.Position.Bias;

/**
* @author Jeanette Winzenburg
*/
public class ContextMenuAuxTextUI extends TextUI {

 private MouseListener mouseHandler;

 public static ComponentUI createUI(JComponent c) {
     return new ContextMenuAuxTextUI(); //单态模式
 }

 public void installUI(JComponent comp) {
     comp.addMouseListener(getMouseListener());//在InstallUI的时候给组件加上鼠标侦听
 }

 public void uninstallUI(JComponent comp) {
     comp.removeMouseListener(getMouseListener());//在卸载UI的时候移除监听
 }



 private MouseListener getMouseListener() {
     if (mouseHandler == null) {
         mouseHandler = createPopupHandler();//创建新的PopupHandler,处理右键弹出事件
     }
     return mouseHandler;
 }

 private MouseListener createPopupHandler() {
     return new ContextMenuHandler(createContextSource());
 }

 private ContextMenuSource createContextSource() {
     return new TextContextMenuSource();
 }

 public void update(Graphics g, JComponent c) {
 }

 public Rectangle modelToView(JTextComponent t, int pos)
         throws BadLocationException {
     // TODO Auto-generated method stub
     return null;
 }

 public Rectangle modelToView(JTextComponent t, int pos, Bias bias)
         throws BadLocationException {
     // TODO Auto-generated method stub
     return null;
 }

 public int viewToModel(JTextComponent t, Point pt) {
     // TODO Auto-generated method stub
     return 0;
 }

 public int viewToModel(JTextComponent t, Point pt, Bias[] biasReturn) {
     // TODO Auto-generated method stub
     return 0;
 }

 public int getNextVisualPositionFrom(JTextComponent t, int pos, Bias b,
         int direction, Bias[] biasRet) throws BadLocationException {
     // TODO Auto-generated method stub
     return 0;
 }

 public void damageRange(JTextComponent t, int p0, int p1) {
     // TODO Auto-generated method stub

 }

 public void damageRange(JTextComponent t, int p0, int p1, Bias firstBias,
         Bias secondBias) {
     // TODO Auto-generated method stub

 }

 public EditorKit getEditorKit(JTextComponent t) {
     // TODO Auto-generated method stub
     return null;
 }

 public View getRootView(JTextComponent t) {
     // TODO Auto-generated method stub
     return null;
 }

}

  • ContextMenuAuxTextUI中添加的ContextMenuHandler
/* * $Id: ContextMenuHandler.java,v 1.5 2005/10/24 13:20:46 kleopatra Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jdesktop.swingx.plaf; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.ActionMap; import javax.swing.JComponent; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; /** * Responsible for showing the default PopupMenu. * * @author Jeanette Winzenburg */ public class ContextMenuHandler extends MouseAdapter { private ActionMap actionMap; private ContextMenuSource contextMenuSource; private JPopupMenu popup; /** * creates a context handler for TextContextMenuSource. * */ public ContextMenuHandler() { this(null); } /** * creates a context handler for the given ContextMenuSource. * Defaults to TextContextMenuSource if source == null. * * @param source */ public ContextMenuHandler(ContextMenuSource source) { contextMenuSource = source; } // --------------------- MouseListener public void mousePressed(MouseEvent e) { maybeShowContext(e);//在鼠标按下时检测是否是除非弹出事件 } public void mouseReleased(MouseEvent e) { maybeShowContext(e);//在鼠标释放时检测是否是除非弹出事件 } private void maybeShowContext(final MouseEvent e) { if (!e.isPopupTrigger() || !e.getComponent().isEnabled())//判断条件:该事件是弹出事件,触发该事件的组件没被禁用 return; if (e.getComponent().hasFocus()) { showContextPopup(e);//显示Popup } else { ((JComponent) e.getComponent()).grabFocus(); SwingUtilities.invokeLater(new Runnable() { public void run() { showContextPopup(e); } }); } } private void showContextPopup(MouseEvent e) { showContextPopup((JComponent) e.getComponent(), e.getX(), e .getY()); } private void showContextPopup(JComponent component, int x, int y) { JPopupMenu popup = getPopupMenu(component, true); popup.show(component, x, y); } /** * @param component * @return */ private JPopupMenu getPopupMenu(JComponent component, boolean synchEnabled) { if (popup == null) { popup = new JPopupMenu(); ActionMap map = getActionMap(component);//得到组件的ActionMap String[] keys = getContextMenuSource().getKeys(); for (int i = 0; i < style="color: rgb(102, 255, 153);">//添加对于的Action到Popup中 } else { popup.addSeparator(); } } } if (synchEnabled) { getContextMenuSource().updateActionEnabled(component, actionMap);//检查哪些Action可用 } return popup; } private ActionMap getActionMap(JComponent component) { if (actionMap == null) { actionMap = getContextMenuSource().createActionMap(component); } else { // todo: replace actions with components? } return actionMap; } private ContextMenuSource getContextMenuSource() { if (contextMenuSource == null) { contextMenuSource = new TextContextMenuSource(); } return contextMenuSource; } }
  • ContextMenuHandler用到的TextContextMenuSource
/* * $Id: TextContextMenuSource.java,v 1.5 2006/05/14 08:19:45 dmouse Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jdesktop.swingx.plaf; import java.util.Map; import javax.swing.ActionMap; import javax.swing.JComponent; import javax.swing.JPasswordField; import javax.swing.text.DefaultEditorKit; import javax.swing.text.JTextComponent; /** * @author Jeanette Winzenburg */ public class TextContextMenuSource extends ContextMenuSource{ String UNDO = "Undo"; String CUT = "Cut"; String COPY = "Copy"; String PASTE = "Paste"; String DELETE = "Delete"; String SELECT_ALL = "Select All"; String[] keys = { DefaultEditorKit.cutAction, DefaultEditorKit.copyAction, DefaultEditorKit.pasteAction, DefaultEditorKit.deleteNextCharAction, null, // separator DefaultEditorKit.selectAllAction };//文本组件的Action Name,ActionMap的Key,Null用来表示一个分隔符号 String[] defaultValues = { CUT, COPY, PASTE, DELETE, null, SELECT_ALL, }; public String[] getKeys() { return keys; } public void updateActionEnabled(JComponent component, ActionMap map) { if (!(component instanceof JTextComponent)) return; JTextComponent textComponent = (JTextComponent) component; boolean selectedText = textComponent.getSelectionEnd() - textComponent.getSelectionStart() > 0;//是否有文本被选中,条件1 boolean containsText = textComponent.getDocument().getLength() > 0;//是否有文本,条件2 boolean editable = textComponent.isEditable();//可否编辑,条件3 boolean copyProtected = (textComponent instanceof JPasswordField);//如果是PasswordField,则不能Copy,条件4 boolean dataOnClipboard = textComponent.getToolkit() .getSystemClipboard().getContents(null) != null;//系统剪切板上是否有数据,条件5 map.get(DefaultEditorKit.cutAction).setEnabled( !copyProtected && editable && selectedText);//Cut可用的条件是 4,3,1均成立 map.get(DefaultEditorKit.copyAction).setEnabled( !copyProtected && selectedText);//Copy可用的条件是 4,1成立 map.get(DefaultEditorKit.pasteAction).setEnabled( editable && dataOnClipboard);//Paste可用的条件是3,5成立 map.get(DefaultEditorKit.deleteNextCharAction).setEnabled( editable && selectedText);//Delete成立的条件是3,1成立 map.get(DefaultEditorKit.selectAllAction).setEnabled(containsText);//selectedAll需要条件2 }
引用来自:

Swing: Context Menu for TextComponents

SwingLabs

JDK 6 Update 7

2 评论  

今天无聊逛了一下java.sun.com,结果发现又有新的JDK更新了,Update7,记得前段时间下载Update6的时候还没多久呢,呵呵,最近Sun的更新比较频繁啊,看来传说中的Update 10也快正式发布了吧。 官方 的Release Note里面提到Update 7 照例干了一些Bug Fix 的活,不过这次附带一个Java Visual VM的工具软件,记得以前看到网上有篇文章,对Java VM的一个诟病之处就在于基于JMX API 无法很好的对VM进行监控,文中似乎还提到JRockit跟IBM的的那个VM比较好的一点就是对VM监控这方面的增强。 为了体验一下这个Visual VM,我装了一下Update 7,不过装完之后没有提示说有这么一个比较重要的特性。其实这里不得不提到一点,JDK安装好后,除了会在控制面板里面添加一个Java 的快捷方式,方便管理WebStart的东东以为就没有其它的快捷方式了,其实Java里面也有很多的好用的工具软件啊,大的比如说Java DB,小的有Native2Ascii,不知道在开始菜单里面新建一个Java 的文件夹,放上常用的快捷方式是不是会更加人性化一点,呵呵。 找这个Visual VM就是靠经验了,在JDK_HOME/bin目录下面,有一个jvisualvm.exe文件,看名字也就知道是它了,双击打开,从UI上来看,这个软件是基于NetBeans开发的了。

  • Splash界面
  • OverView界面
  • Monitor界面
  • Threads界面
  • Profiler界面
从界面上看还是比较简洁的,左边是树形结构,自动显示当前本机所运行的Java程序,还可以添加远程的Java VM,其中括号里面的PID指的是进程ID。OverView界面显示VM启动参数以及该VM对应的一些属性。Monitor界面则是监控Java堆大小,Permgen大小,Classes和线程数量。Profiler界面比较有趣,看样子似乎可以动态的对某个Java程序进行调优了。不过我没试用这个功能,感觉要调优还是在Netbeans里面比较自然一点,起码有代码,没代码调优了用处也不大。而且这里还有个问题,有些VM是没有Threads跟Profiler界面的,不知道是什么原因,像我截图里面的Weblogic的Server就没有这两个界面。

QT Jambi Clock

0 评论  

学程序也有好几年了吧,呵呵,从C程序开始,一直都想要写一个比较漂亮点的桌面程序,不过一直都有这样那样的问题,C++学得太烂了,学到最后还是只会写Console程序,什么是Console程序?就是在命令行(我叫它黑屏)里面运行的程序。还记得那个时候跟阳春一起去参加学校里面的C++程序大赛,呵呵,当然,我的水平很菜的,都靠阳春了,也混了个三等奖,不过一来多半是阳春出的力,再者我也觉得Console的程序实在太丑了。参考程序大赛之前还听过一节钱能的课,大学老师里面我还记得名字不多了,钱能算一个,主要这个名字还是比较牛逼的,有钱就能,哈哈。都说他的C++讲的很好,连那本红红的C++程序书也是他主编的,自然有点崇拜的意思了,不过现在都记得,为了运行在BolandC++6.0里面运行Console程序,钱老师让我们在每个程序的最后都会有一句话大概是cin>>。当时还有点莫名,不过其实这句话学过C++的应该知道,是等待命令行输入的,之所以有这句话,是因为每次运行完Console程序后BolandC++会自动退出这个程序,一般来讲,应该显示Press any key to Continue...这可能是BC6的Bug吧。 后来数据结构课的时候有一个作业,大概是模拟一个冰淇淋店,也是用Console的,因为当时还没写过不是Console的程序,也一直觉得用MFC挺难写的,大部分人应该都这样吧,所以那年的作业几乎都是用Console写的,我写这个程序花了很长时间,用VC6写的,当时就是一开始写很多代码,然后编译,在心里默默祈祷不报错,结果往往是报好几十个编译错误,让人眼花缭乱,无从下手,我C++写的少,就用过VC6,BC6,不过我总觉得VC6就是Shit,编译出来的错误信息千奇百怪,但就是不指向真正错误的地方,这点后来在接触Java以后深有感触。冰淇淋店的程序写到后来在要交作业之前终于能运行了,不过程序还有Bug,当时也基本不会调试,调了好久一直没通,眼看就要到最后期限了,就用了上面提到那招,老师当时坚持作业是让她的研究生来做的,他们都是看程序的运行有没有正常结束,恰好我的程序不能正常结束,我就自己Cout一行,“Press any key to Continue。。。”,也让我蒙过了,哎,惭愧啊。。。 再后来学Java了,应该是大二暑假吧,把电脑带回家,借了一本Java的书,主要也就是看中了书里面有很简单易学的GUI界面编程的东西,不像以前那些书,通篇看下来还不知所云,就这样进入了Java的怀抱。 后来才知道,Swing架构的确不错,MVC,轻量级的UI,不过这些都无法弥补Swing的致命弱点,运行速度慢,很多操作系统平台级别的API很难调用,比如你要写一个半透明的程序,要写一个不规则窗口,这些可以实现,一般人要实现这些那真太难了,要用到JNI,要封装C++程序来调本地API,再通过Java来调这个C++程序,太麻烦了,我曾经为了这两个问题搜索了好几天的百度,Google,也有些结果,不过不是因为效率太低,就是因为程序太难用而放弃了。而且其实Swing也不够灵活,说这句话是看了QT Jambi后才说,之前也觉得Swing是比较灵活,你可以通过Java2D绘制出很炫的程序,也有很多开源的框架,不过跟QT Jambi比起来,那还是有差距的。 QT是我偶然间发现的,当时就想找找C++里面有没有标准的GUI库,也是想试试看在NetBeans里面编个C++的GUI程序,搜索到很多第三方的C++库,也不知道哪个好,就一个一个的放到Google里面去,看返回的结果,谁最多就选谁了。说实话QT这个名字我不喜欢,不太专业,打开了他的官方首页一看,没想到QT还有For Java Developer的,就把这个ForJava 的版本Down了下来,里面有一个Exe的程序,打开,是QT的一些例子,一个个看下来,哇靠,效果刚刚的,看了一下这个Demo的源代码,似乎不是很难,就想要用它来写一个程序,Google一下,想找个简明教程来着,结果很让人失望,QT在C++领域是比较牛了,用得人很多,不过在Java领域几乎还是空白,没什么例子好参考,只剩下这个Demo了.上个星期天的时候把那个IP程序改得差不多了,不想改了,就试着去改QT JambiDemo里面的一个例子,这个例子在屏幕上画了一个圆形的时钟,窗口是圆形的,觉得挺有趣的,就基于这个程序,原程序是通过QT的2D绘制出来,比较丑,就想给它加个背景,搞了一下午,总算加好背景了。不过苦于没有好看的,合适的背景,星期一上班的时候去搜索了一下现有的Clock程序,找到一个也是绘制一个圆形的时钟,背景是BmP图片,呵呵,就用这个了,把这个程序里面的图片结合我已有的程序,效果还不错,后面就模仿它的功能做了一个背景样式选择. 完整源代码下载

What is QT Jambi

0 评论  

百度百科里面的解释: QT软件 Qt是一个多平台的C++图形用户界面应用程序框架。它提供给应用程序开发者建立艺术级的图形用户界面所需的所用功能。Qt是完全面向对象的很容易扩展,并且允许真正地组件编程 自从1996年早些时候,Qt进入商业领域,它已经成为全世界范围内数千种成功的应用程序的基础。Qt也是流行的Linux桌面环境KDE 的基础,KDE是所有主要的Linux发行版的一个标准组件。 Qt支持下述平台 MS/Windows - 95、98、NT 4.0、ME、2000 Unix/X11 - LinuxSun Solaris、HP-UX、Compaq Tru64 UNIX、IBM AIX、SGI IRIX和其它很多X11平台 Macintosh - Mac OS X Embedded - 有帧缓冲(framebuffer)支持的Linux平台。 Qt是Trolltech公司的一个产品。 Qt被按不同的版本发行: Qt企业版和Qt专业版 提供给商业软件开发。它们提供传统商业软件发行版并且提供免费升级和技术支持服务。如果要获得最新报价,请浏览Trolltech公司网站的价格和可行性页面,或者与sales@trolltech.com联系。企业版比专业版多一些扩展模块。 Qt自由版是Qt仅仅为了开发自由和开放源码软件 提供的Unix/X11版本。在Q公共许可证和GNU通用公共许可证 下,它是免费的。最新的版本可以在这里下载。 Qt/嵌入式自由版是Qt为了开发自由软件提供的嵌入式版本。在GNU通用公共许可证下,它是免费的。 不过百度百科所描述的QT应该比较老了,现在的最新版本QT4,应该是支持Windows XP,Vista了。 那什么是QT Jambi呢,官方的解释翻译如下(括号里面是我的注解): QT Jambi是一个跨平台,支持富客户端Java应用程序框架(原文:Rich client Javaapplica framework), 它包含了丰富的类库和完整的开发工具套件以支持其所谓富客户端Java程序开发。 后面省略XX字,都是吹嘘之词。

  • QT Jambi 架构
QT跟AWT,SWT无异,都是通过JNI调用C++的API,实现界面编程,只不过AWT,SWT都是调用的本机API,QT为了实现跨平台的特性,所 有的界面元素都是其基于本机API的一个轻量级封装,QT就像Swing,界面元素多半是自己绘制出来的。而QT Jambi 通过JNI(Java native interface)绑定到对应的Java代码。 以下图片即为官方对QT Jambi 架构的一个描述:
  • 开发工具:
目前的QT Jambi 4.4有Eclipse的开发插件,该插件提供了可视化的界面编辑,虽然没有NetBeans里面NB编辑器那么牛,不过也算能将就了。本来一直想不喜欢用Eclipse编代码,这下要写QT Jambi也就没办法了。
  • QT Jambi类库:
官方上没明说,不过似乎QT4里面提供的NetWork,OpenGL,Phonon,SQL,SVG,Webkit,XML都能在QT Jambi里面找到对应的Java包。 QT4的界面设计相当灵活强大,QT Jambi也一样,不过可能由于多方面的原因,QT Jambi算一个冷门产品了,呵呵,不过如果要想用Java写一个界面外观很Native,界面比较灵活的程序,QT Jambi应该是一个不错的选择。