﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-treenode-随笔分类-SWT,JFace和RCP</title><link>http://www.blogjava.net/treenode/category/11825.html</link><description>在路上。</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 03:15:11 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 03:15:11 GMT</pubDate><ttl>60</ttl><item><title>在SWT中实现自绘Combo</title><link>http://www.blogjava.net/treenode/archive/2006/07/06/56900.html</link><dc:creator>TreeNode</dc:creator><author>TreeNode</author><pubDate>Thu, 06 Jul 2006 02:08:00 GMT</pubDate><guid>http://www.blogjava.net/treenode/archive/2006/07/06/56900.html</guid><wfw:comment>http://www.blogjava.net/treenode/comments/56900.html</wfw:comment><comments>http://www.blogjava.net/treenode/archive/2006/07/06/56900.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/treenode/comments/commentRss/56900.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/treenode/services/trackbacks/56900.html</trackback:ping><description><![CDATA[可能是为了保持平台独立性，SWT没有开放许多控件的自定义接口。例如，Win32中的Button、Label、List和ComboBox都是可以自绘（Owner Draw）的，但是SWT并没有把这些绘制方法开放出来。在最新的3.2版本中添加的一个新特性是Table和Tree现在支持Custom Draw了（但是并未整合到Viewer体系中），不过对于上述控件的支持仍付阙如。<br /><br />上一次，我实现了一个自绘的按钮。现在，看到有人询问是否可以在Combo的列表中加入图像。其实这相当容易，只要重载Combo Widget并把自绘接口暴露出来即可。以下是简单的代码示例：<br /><br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">package</span><span style="COLOR: #000000"> org.eclipse.swt.widgets;<br /><br /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> java.io.</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">;<br /><br /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> org.eclipse.swt.SWT;<br /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> org.eclipse.swt.graphics.</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> org.eclipse.swt.internal.win32.</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">;<br /><br /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> CustomCombo </span><span style="COLOR: #0000ff">extends</span><span style="COLOR: #000000"> Combo<br />{<br />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> CustomCombo( Composite parent, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> style )<br />    {<br />        </span><span style="COLOR: #0000ff">super</span><span style="COLOR: #000000">( parent, style );<br /><br />        </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"><br />        {<br />            InputStream is </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> getClass().getResourceAsStream( </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">bullet.gif</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> );<br />            image </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Image( getDisplay(), is );<br />            is.close();<br />        }<br />        </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000"> ( IOException e )<br />        {<br />            e.printStackTrace();<br />        }<br />        </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> CB_SETITEMHEIGHT </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0x0153</span><span style="COLOR: #000000">;<br /><br />        OS.SendMessage( handle, CB_SETITEMHEIGHT, </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">, </span><span style="COLOR: #000000">24</span><span style="COLOR: #000000"> );<br />        OS.SendMessage( handle, CB_SETITEMHEIGHT, </span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">, </span><span style="COLOR: #000000">24</span><span style="COLOR: #000000"> );<br />    }<br /><br />    @Override<br />    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> widgetStyle()<br />    {<br />        </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> CBS_OWNERDRAWFIXED </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0x0010</span><span style="COLOR: #000000">;<br />        </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> CBS_HASSTRINGS </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0x0200</span><span style="COLOR: #000000">;<br />        </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> final int CBS_OWNERDRAWVARIABLE = 0x0020;</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">super</span><span style="COLOR: #000000">.widgetStyle() </span><span style="COLOR: #000000">|</span><span style="COLOR: #000000"> CBS_OWNERDRAWFIXED </span><span style="COLOR: #000000">|</span><span style="COLOR: #000000"> CBS_HASSTRINGS;<br />    }<br /><br />    @Override<br />    </span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> checkSubclass()<br />    {<br />    }<br /><br />    @Override<br />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> dispose()<br />    {<br />        image.dispose();<br />        </span><span style="COLOR: #0000ff">super</span><span style="COLOR: #000000">.dispose();<br />    }<br /><br />    </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"> @Override<br />    LRESULT wmMeasureChild( int wParam, int lParam )<br />    {<br />        MEASUREITEMSTRUCT mis = new MEASUREITEMSTRUCT();<br />        OS.MoveMemory( mis, lParam, MEASUREITEMSTRUCT.sizeof );<br />        mis.itemHeight = 40;<br />        OS.MoveMemory( lParam, mis, MEASUREITEMSTRUCT.sizeof );<br />        return null; // super.wmMeasureChild( wParam, lParam );<br />    } </span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /><br />    @Override<br />    LRESULT wmDrawChild( </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> wParam, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> lParam )<br />    {<br />        DRAWITEMSTRUCT dis </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> DRAWITEMSTRUCT();<br />        OS.MoveMemory( dis, lParam, DRAWITEMSTRUCT.sizeof );<br /><br />        GC gc </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> GC( </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> DCWrapper( dis.hDC ) );<br />        Rectangle rc </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Rectangle( dis.left, dis.top, dis.right </span><span style="COLOR: #000000">-</span><span style="COLOR: #000000"> dis.left,<br />                dis.bottom </span><span style="COLOR: #000000">-</span><span style="COLOR: #000000"> dis.top );<br />        Display display </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> getDisplay();<br />        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( (dis.itemState </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> OS.ODS_SELECTED) </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> )<br />        {<br />            gc<br />                    .setBackground( display<br />                            .getSystemColor( SWT.COLOR_LIST_SELECTION ) );<br />            gc.setForeground( display<br />                    .getSystemColor( SWT.COLOR_LIST_SELECTION_TEXT ) );<br />            gc.fillRectangle( rc );<br />        }<br />        </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br />        {<br />            gc.setBackground( display<br />                    .getSystemColor( SWT.COLOR_LIST_BACKGROUND ) );<br />            gc.setForeground( display<br />                    .getSystemColor( SWT.COLOR_LIST_FOREGROUND ) );<br />            gc.fillRectangle( rc );<br />        }<br />        String text </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> getItem( dis.itemID );<br />        gc.drawImage( image, dis.left </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">, dis.top </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> );<br />        gc.drawText( text, dis.left </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">20</span><span style="COLOR: #000000">, dis.top );<br /><br />        gc.dispose();<br /><br />        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">;<br />    }<br /><br />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> DCWrapper </span><span style="COLOR: #0000ff">implements</span><span style="COLOR: #000000"> Drawable<br />    {<br />        </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">    hdc;<br /><br />        DCWrapper( </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> hdc )<br />        {<br />            </span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">.hdc </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> hdc;<br />        }<br /><br />        </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> internal_new_GC( GCData data )<br />        {<br />            </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> hdc;<br />        }<br /><br />        </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> internal_dispose_GC( </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> handle, GCData data )<br />        {<br />        }<br />    }<br /><br />    </span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000"> Image    image;<br />}<br /></span></div><p><br />值得说明的是，如果设置Combo为OwnerDraw Variable风格，则必须重载wmMeasureChild方法来指定每一项的高度。如果使用OwnerDraw Fixed风格，则只需要在构造的时候发送一条CB_SETITEMHEIGHT消息就行了。<br /></p><p> 另外一种值得考虑的选择是将Win32的ComboBoxEx控件包装成SWT Widget。不过，这需要转换若干结构并提供接口，Win32的ImageList管理机制和SWT的Image包装方法差别比较大，使得这种方法实现起来麻烦的多。<br /></p><img src ="http://www.blogjava.net/treenode/aggbug/56900.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/treenode/" target="_blank">TreeNode</a> 2006-07-06 10:08 <a href="http://www.blogjava.net/treenode/archive/2006/07/06/56900.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用cglib代码生成避开烦人的内部类</title><link>http://www.blogjava.net/treenode/archive/2006/06/27/55289.html</link><dc:creator>TreeNode</dc:creator><author>TreeNode</author><pubDate>Tue, 27 Jun 2006 03:29:00 GMT</pubDate><guid>http://www.blogjava.net/treenode/archive/2006/06/27/55289.html</guid><wfw:comment>http://www.blogjava.net/treenode/comments/55289.html</wfw:comment><comments>http://www.blogjava.net/treenode/archive/2006/06/27/55289.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/treenode/comments/commentRss/55289.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/treenode/services/trackbacks/55289.html</trackback:ping><description><![CDATA[
		<p>在上回的blog中，我抱怨过用Java用内部类来实现事件回调的机制是多么难看和麻烦。在这段时间里，我一直在考虑是否有什么方法可以不用内部类而实现同样的效果。因为Java语言本身的限制，所以常规方法是行不通的。有人建议用反射——的确通过反射可以调用任意的方法，但是反射效率不佳，对频繁发生的事件或许不太合适。动态代理也不能解决方法映射的难题。我似乎走进了死胡同。</p>
		<p>既然此路不通，那么C#是如何实现delegate的呢？过去也曾听闻过一些内幕，不过这次被逼才真的下决心认真去看这方面的东西。原来M$使用的是代码生成的技术：对于每个delegate，C#都会为它生成一个派生于MulticaseDelegate的对象，其中实现了一个和delegate签名相同的方法。同时，对delegate的操作符+=和-=也会被编译器处理成对MulticaseDelegate方法的调用。</p>
		<p>知道了这一点，接下来就需要看看Java中有没有类似的代码生成技术了。有意思的是，查找的时候发现有消息说，Java 6.0（Mutang）中将会提供动态代码生成的功能。这的确很吸引人，不过Java6还在Beta阶段，眼下还指望不上。其他比较出名的方法就是Apache becl和Objectweb ASM了。这两个库都比较底层，不过还有一个开源的项目——cglib——它在内部使用了asm，不过提供了较多的实用功能。据说Hibernate和Spring都用到了这个东西。研究这个库的时候，我一眼看到了MethodDelegate类——很明显这就是我要找的东西了。</p>
		<p>MethodDelegate的设计思想很类似于C#的delegate——将接口调用转发给类的一个成员函数。不过阅读文档的时候我发现一个问题。MethodDelegate要求其所实现的接口必须只有一个公共方法，但是SWT中的许多事件接口都有不止一个方法；比如，SelectionListener就有widgetSelected和idgetDefaultSelected两个方法。因此要在SWT中使用MethodDelegate，还</p>
		<p>必须再多实现另外一层转发。</p>
		<p>了解手段，接下来的事情就不难了。总结起来，需要的步骤大致如下：<br />1、为每种需要实现的事件声明一个接口。这是MethodDelegate的要求。<br />2、用一个类实现SWT的事件接口，并将特定的接口调用转发到第一步所实现</p>
		<p>的接口。<br />3、用MethodDelegate提供的方法，声明事件处理对象（Event Handler </p>
		<p>Target，通常为主窗体或主部件）要实现上述的事件接口。下面就来实现一下。为了简单起见，将需要实现的接口声明为事件转发类的内部接口，以避免维护太多接口文件（因为该接口只需要声明一个方法，所以不会把外部类搞得太过复杂。）例如，处理部件选择事件（widgetSelected）的类可以如下实现：</p>
		<p>package org.yuhao.swt.events;</p>
		<p>import net.sf.cglib.reflect.MethodDelegate;</p>
		<p>import org.eclipse.swt.events.*;</p>
		<p>public class WidgetSelectedHandler implements SelectionListener<br />{<br /> public WidgetSelectedHandler( Object target, String </p>
		<p>methodName )<br /> {<br />  delegate = (IWidgetSelectedDelegate) </p>
		<p>MethodDelegate.create( target,<br />    methodName, </p>
		<p>IWidgetSelectedDelegate.class );<br /> }</p>
		<p> public void widgetDefaultSelected( SelectionEvent e )<br /> {<br /> }</p>
		<p> public void widgetSelected( SelectionEvent e )<br /> {<br />  delegate.invoke( e );<br /> }</p>
		<p> public void invoke( SelectionEvent e )<br /> {<br /> }</p>
		<p> public interface IWidgetSelectedDelegate<br /> {<br />  void invoke( SelectionEvent e );<br /> }</p>
		<p> private IWidgetSelectedDelegate delegate;<br />}</p>
		<p>这个接口虽然只有外部类用到，但是必须声明为public的，否则运行会出错（我想大概是因为代码生成以后还是外部类，需要公开访问权限）。为了简化调用，再声明一个处理事件的辅助类EventHandler，专门管理将各种事件转发到相应的Handler的工作：</p>
		<p>public class EventHandler<br />{<br /> public EventHandler( Object target )<br /> {<br />  this.target = target;<br /> }</p>
		<p> public void handleSelected( Button btn, String methodName )<br /> {<br />  btn.addSelectionListener( new </p>
		<p>WidgetSelectedHandler( target, methodName ) );<br /> }<br /> private Object target;<br />}</p>
		<p>这样，在窗口中就可以简单的如下处理事件：<br />public MainShell extends Shell()<br />{<br />  public MainShell( Display display )<br /> {<br />  ......<br />  handler = new EventHandler( this );<br />  handler.handleSelected( btn, "btn_clicked" );<br /> }</p>
		<p> public void btn_clicked( SelectionEvent e )<br /> {<br />  ...<br /> }<br />}</p>
		<p>这里还需要注意：1、任何事件处理方法必须声明为public的。这样似乎有违面向对象的封装原则，不过实际上并不会造成什么大问题。2、事件方法的签名必须和对应的事件方法相同。例如，widgetSelected方法有一个SelectionEvent参数，那么处理该事件的btn_clicked方法也必须有且只有这一个参数。如果写错了，那么运行的时候会抛出异常，说找不到指定的方法。这还是需要程序员的细心来保证。还算幸运的是出错的提示非常明显，不必担心使用了过度复杂的技术而找不到真正的出错点。<br /></p>
<img src ="http://www.blogjava.net/treenode/aggbug/55289.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/treenode/" target="_blank">TreeNode</a> 2006-06-27 11:29 <a href="http://www.blogjava.net/treenode/archive/2006/06/27/55289.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SWT: 深入内幕之消息机制探秘（上篇）</title><link>http://www.blogjava.net/treenode/archive/2006/06/03/50114.html</link><dc:creator>TreeNode</dc:creator><author>TreeNode</author><pubDate>Sat, 03 Jun 2006 04:46:00 GMT</pubDate><guid>http://www.blogjava.net/treenode/archive/2006/06/03/50114.html</guid><wfw:comment>http://www.blogjava.net/treenode/comments/50114.html</wfw:comment><comments>http://www.blogjava.net/treenode/archive/2006/06/03/50114.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.blogjava.net/treenode/comments/commentRss/50114.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/treenode/services/trackbacks/50114.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 本文试图透过SWT面向对象的封装，深入研究界面框架的构造中最复杂也可以说是最有趣的问题之一——即界面框架如何以面向对象的方式实现操作系统底层的消息机制。&nbsp;&nbsp;<a href='http://www.blogjava.net/treenode/archive/2006/06/03/50114.html'>阅读全文</a><img src ="http://www.blogjava.net/treenode/aggbug/50114.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/treenode/" target="_blank">TreeNode</a> 2006-06-03 12:46 <a href="http://www.blogjava.net/treenode/archive/2006/06/03/50114.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>