主题 : 让SWT组件在Windwos平台下实现更丰富的样式
vii779 离线
级别: CEC贵宾
显示用户信息 
0  发表于: 2006-07-13   

让SWT组件在Windwos平台下实现更丰富的样式

闲着无事,试了一下SWT中Tree和Table在Windows下的样式。

为了跨平台和兼容性,SWT组件牺牲了本地平台组件一些比较有特色的特性。

也许你会抱怨SWT为什么没有Windows中资源管理器右边那样的视图组件,可以显示大图标、小图标,列表,详细资料。其实SWT中是有的,而且你天天见到它,天天使用它,它就是Table。

实际上也就是SysListView32控件。熟悉win32编程的人一定对它不陌生。遗憾的是,SWT没有
完全封装SysListView32的全部特性,只封装了详细资料样式,可能是为了照顾跨平台吧。

如果你的程序就只在Win32平台下运行,那么抛弃跨平台带来的约束吧。来尽情的使用本地组件提供
的丰富特性。

做了一个简单试验,可以做到树去掉加号,连接线,热点选择等样式。表格可以支持小图标,列表,详细资料。大图标样式还不可以显示图标,因为Table中没有设置大图标的方法。

如果谁有兴趣,可以自己封装一个ExTree,ExTable,以实现Windows平台的丰富特性。

示例树样式

示例表样式

描述:示例代码
附件: StyleTest.java (10 K) 下载次数:97
清空我的评分动态本帖最近评分记录: 共1条评分记录
yipsilon 财富 +10 2006-07-13 -
隐藏评分记录
treenode 离线
级别: CEC高级程序员
显示用户信息 
1  发表于: 2006-07-14   
>>因为Table中没有设置大图标的方法

试过,确实不容易。因为Win32的ListView要求大图标和小图标具有同样的图标索引,而SWT只能使用Image对象,不支持索引。而且Table只实现了小图标,自己创建大图标的话,大小图标列表的索引同步很困难。

也许重新做一个不受限制的控件是更好的办法。
vii779 离线
级别: CEC贵宾
显示用户信息 
2  发表于: 2006-07-14   
SWT已经 封装了Win32的ImageList对象,而Table的小图标也是通过ImageList实现的。
看一下Table中创建小图标的代码,就可以验证这一点

int imageIndex (Image image) {
   if (image == null) return OS.I_IMAGENONE;
   if (imageList == null) {
       Rectangle bounds = image.getBounds ();
       imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
       int index = imageList.indexOf (image);
       if (index == -1) index = imageList.add (image);
       int hImageList = imageList.getHandle ();
       /*
       * Bug in Windows. Making any change to an item that
       * changes the item height of a table while the table
       * is scrolled can cause the lines to draw incorrectly.
       * This happens even when the lines are not currently
       * visible and are shown afterwards. The fix is to
       * save the top index, scroll to the top of the table
       * and then restore the original top index.
       */
       int topIndex = getTopIndex ();
       if (topIndex != 0) {
           setRedraw (false);
           setTopIndex (0);
       }
       OS.SendMessage (handle, OS.LVM_SETIMAGELIST, OS.LVSIL_SMALL, hImageList);
       if (headerImageList != null) {
           int hwndHeader = OS.SendMessage (handle, OS.LVM_GETHEADER, 0, 0);
           int hHeaderImageList = headerImageList.getHandle ();
           OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, hHeaderImageList);
       }
       fixCheckboxImageList (false);
       if (itemHeight != -1) setItemHeight (false);
       if (topIndex != 0) {
           setTopIndex (topIndex);
           setRedraw (true);
       }
       return index;
   }
   int index = imageList.indexOf (image);
   if (index != -1) return index;
   return imageList.add (image);
}

如果想实现大图标,可以写一个类继承Tabel,要和Table放在一个包中,然后实现创建大图标的代码就可以了。
binxiao 离线
级别: CEC高级程序员
显示用户信息 
3  发表于: 2006-07-14   
好好学习,天天向上
treenode 离线
级别: CEC高级程序员
显示用户信息 
4  发表于: 2006-07-14   
创建大图像列表很容易。问题是:如果你往小图标里面加一个图像,再往大图标里面加一个,但是这两个图像返回的索引不一样,你怎么办?给TableItem指定哪个图像?
看过Display.getImageList的实现,它是用自己的逻辑维护图像列表的,多个大小相同的图像实际上共用一个Image,因此图像在这个ImageList中出现的顺序很难控制。
vii779 离线
级别: CEC贵宾
显示用户信息 
5  发表于: 2006-07-14   
只需要写两个类ExTable,和ExTabelItem. 分别继承Table和TableItem.
ExTableItem提供方法setLargeImage(Image image),用于设置大图标。
ExTable提供largeImageIndex方法,用于创建大图标列表。

写了一个例子,比较简单,可做为一个参考。例子中没用处理资源释放等相关问题,只着重于如何实现大图标。



除了通过继承Tabel的方式外,还想到了另一种方式,未完待续。
[ 此贴被vii779在2006年07月14日 15:25重新编辑 ]
描述:示例代码
附件: demo.rar (3 K) 下载次数:53
treenode 离线
级别: CEC高级程序员
显示用户信息 
6  发表于: 2006-07-14   
你还是没明白问题在哪。只用一个Table是看不出来的。
不妨把这段代码加到你的例子里面,table = new ExTable(this, SWT.BORDER);这句话前面。
看看大图标还能不能出来。

Table t0 = new Table(this, SWT.BORDER);
GridData d0 = new GridData(GridData.FILL_HORIZONTAL);
d0.horizontalSpan = 2;
t0.setLayoutData( d0 );
TableItem ti0 = new TableItem(t0, SWT.NONE);
ti0.setText( "1122" );
ti0.setImage( Display.getCurrent().getSystemImage(SWT.ICON_ERROR) );
vii779 离线
级别: CEC贵宾
显示用户信息 
7  发表于: 2006-07-14   
我明白你的意思,主要是图像顺序控制的问题, 大图标的顺序可能会和小图标的顺序不能保持一致。
这个总会有办法解决的,不一定要Display来管理,可以自己通过代码来维护大图标和小图标的顺序。

只要把这个问题解决了,基本就可以了。
[ 此贴被vii779在2006年07月14日 16:19重新编辑 ]
treenode 离线
级别: CEC高级程序员
显示用户信息 
8  发表于: 2006-07-14   
Table里面小图标的控制是依赖于Display的。除非修改SWT源代码,否则没法改它。
能做的就只能是让大图标跟着小图标走。
所以我才说,与其在这个限制多多的Table上面再加自己的逻辑控制,还不如抛开它,把Win32 ListView做一个完整的封装恐怕还更容易。
vii779 离线
级别: CEC贵宾
显示用户信息 
9  发表于: 2006-07-14   
这个并不是做不到,而且并不需要改SWT的源代码,所做的只是在扩展类里面,维护小图标和大图标的
的顺序,在创建小图标的列表的时候,也同时创建一个大图标列表,在摧毁小图标的时,同时去摧毁大图标列表里面的的大图标,始终保持两个列表里面图标顺序的一致。这点工作量,比重新封装一个ListView可小的多了。
treenode 离线
级别: CEC高级程序员
显示用户信息 
10  发表于: 2006-07-14   
说起来容易做起来难啊。你得把setImage藏起来,不然用户一调这个函数,你辛辛苦苦维护的顺序又乱掉了。
而且Win32的ImageList_AddIcon只能在末尾添加,没有一个ImageList_InsertIcon可以从中间任意位置上添加。要是自己维护的话这里也要多费手脚。
再次列表啊详细资料啊这些SWT都没有提供,有的常量也没有定义。反正这些总归是要自己加上去的,一起做了不更好?而且我觉得,如果真做到这份上,跟原来的Table基本上关系已经不大了,这就应当是一个全新的部件。

当然,修修补补也未尝不可。我个人是比较倾向于保持概念完整性, !(ListView instanceof Table)。如果需求简单的话,那么在原有基础上修改可能是更合适的。
vii779 离线
级别: CEC贵宾
显示用户信息 
11  发表于: 2006-07-14   
谁有兴趣封装一套完整的SWT的Window专用组件库啊,那可真是功德无量了。
treenode 离线
级别: CEC高级程序员
显示用户信息 
12  发表于: 2006-07-14   
我在sf.net上看到的几个SWT相关的项目发展情况似乎都不是很好。不敢乐观
vii779 离线
级别: CEC贵宾
显示用户信息 
13  发表于: 2006-07-14   
一直到现在,都没用形成一个成熟的SWT组件库市场。感觉有点悲哀。
vii779 离线
级别: CEC贵宾
显示用户信息 
14  发表于: 2006-07-14   

经过一番研究,发现根本不需要维护大图标列表和小图标列表的顺序一致性。

只需要判断一下当前Table的样式,根据当前的样式,来选择需要那个列表中的图标。

只要做如下改动

int imageIndex(Image image) {
  
  if(imageList!=null){
   int bits = OS.GetWindowLong(handle, OS.GWL_STYLE);
   bits &= ExTable.LVS_TYPEMASK;
   if(bits==ExTable.LVS_ICON && currentExItem!=null){
    //如果是大图标样式,返回大图标
    return largeImageIndex(currentExItem.getLargeImage());
   }
  }
  return super.imageIndex(image);
 }

附上修正后的代码,如有不对的地方,还请指正

描述:修正后
附件: demo.rar (3 K) 下载次数:48
泽牛内尔 离线
级别: CEC程序员
显示用户信息 
15  发表于: 2006-07-16   
进来学习一下
世上无难事,只怕有心人!
treenode 离线
级别: CEC高级程序员
显示用户信息 
16  发表于: 2006-07-17   
确实是可以的。
很意外SWT每次重画的时候都要调用imageIndex N多次,很低效的做法。
也许这就是跨平台的代价吧。
thrytku 离线
级别: CEC高级程序员
显示用户信息 
17  发表于: 2006-08-22   
学习中~~~
boolean.cn 离线
级别: CEC程序员
显示用户信息 
18  发表于: 2009-07-02   
还不错,学习了
wyl8491797 离线
rcp 爱好者
级别: CEC中级程序员
显示用户信息 
19  发表于: 2009-07-02   
谢谢
描述
快速回复

验证问题:
Eclipse技术的官方网站域名是?(不加 www) 正确答案:eclipse.org
按"Ctrl+Enter"直接提交
上一个 下一个
      辽ICP备05021625号