對于Java來說,GUI開發一直都是項比較頭疼的事情。從AWT的功能奇缺,到Swing的臃腫不堪,往如夢魘般困擾著Java開發人員。
于是,有一群人開始走向了邪路……
這群誤入岐途的人(至少Sun是這么認為的……),走出了自己的一條路,名為SWT(Standard Widget Toolkit)的不歸路(Sun,Sun|||)。
說起SWT冒著被詬病為邪惡所換取的,無外以下幾點:
1.徹底摒棄了AWT/Swing,某種意義上甚至架空了JVM,比如其通過dispose()即時釋放資源。(當然,大家也都知道這意味著什么)
2.功能幾乎全用本地系統完成,所以其界面與本地程序界面也高度一致,一改Java GUI的沉悶,令人眼前一亮。
3.支持本地API調用,也就是說無論本地系統能實現什么,都可以通過SWT照樣實現出來。
4.使用"用戶線程"作為唯一線程,只有在這個線程中才能調用對構件或某些圖形API的訪問操作,減少圖形操作時線程錯誤。但也允許間接的在非用戶線程的進行圖形構件的訪問操作。
5.在Windows下運行速度有保證,明顯超越AWT/Swing,且較穩定。
6.目前已有較豐富的組件庫,有JFace等輔助項目,借助于IDE之利,開發GUI程序速度N快……
但是,只所以被稱為邪道,也不是空穴來風,它的缺陷也是顯而易見的,比如:
1.JNI調用耗費的時間是不能忽略的。JNI調用速度要比普通Java方法調用慢好幾倍甚至幾十倍。即便是在Java 6中,這種情況并沒有改善。且Swing絕大部分是用Java平臺模擬出的組件,這個過程都在一個系統平臺內完成。而SWT是部分在本地系統完成,部分在Java平臺完成,進行操作時要在這兩個平臺之間需要進行頻繁的數據交互。SWT并沒有從根本上解決效率問題。
2.Swing可以享受JVM的特殊待遇,進行特殊優化,比如inline,JIT代碼,Swing事件隊列對于事件的預處理(合并Paint事件,批處理Java 2D光柵指令等),這就像本地組件可以利用操作系統進行優化一樣。而SWT由于采用本地操作,無法完成。
3.SWT只能自頂向下地構建GUI。因此,如果沒有父容器,子控件也就不存在,父容器無法在以后任意改變。不如AWT/Swing靈活。
4.在目前來講,SWT還是一個有限的圖形環境(Sun,依舊是Sun)。到目前為止,它對于Java2D和Java3D的支持還不怎么好。
5.SWT在Windows下速度雖快,是占了Microsoft提供的大量API之利,在其他平臺上則持平或較慢于AWT/Swing。
6.與AWT/Swing不同,SWT和JFace并不是Java技術的標準配置,需要在將JAR文件放到Java CLASSPATH中,并將DLL文件放到系統PATH中才能運行,較AWT/Swing更繁瑣,如果某天Sun大神發威,和標準JRE兼容都可能成為問題。
兩種論調勢成水火,各不相下,似乎都要徹底壓到另一方才可罷休。
其實我認為大可不必,使用何種技術,大體上只有開發人員才會關心,技術外的那些才是用戶所關心的。開發人員間再怎么爭辯,其實在外人眼里都是無意義的窩里斗罷了。
比如,SWT可以包含AWT/Swing,而在AWT/Swing下,要實現SWT的功能也是輕而易舉的。
我舉幾個程序的例子。
AWT/Swing與SWT透明窗體實現的比較:
在SWT中,由于高度集成本地環境,能夠完成很多AWT/Swing力所不能及,很Cool的工作,比如半透明的窗體,代碼如下:
package
org.loon.framework.dll.test;
import
org.eclipse.swt.SWT;
import
org.eclipse.swt.graphics.Point;
import
org.eclipse.swt.internal.win32.OS;
import
org.eclipse.swt.internal.win32.TCHAR;
import
org.eclipse.swt.layout.FillLayout;
import
org.eclipse.swt.widgets.Display;
import
org.eclipse.swt.widgets.Shell;
/**
*<p>
*Title:LoonFramework
*</p>
*<p>
*Description:
*</p>
*<p>
*Copyright:Copyright(c)2007
*</p>
*<p>
*Company:LoonFramework
*</p>
*
*
@author
chenpeng
*@email:ceponline@yahoo.com.cn
*
@version
0.1
*/
public
class
SWTTransTest
{
/**
*
@param
args
*/
public
static
void
main(String[]args)
{
Displaydisplay
=
new
Display();
Shellshell
=
new
Shell(display,SWT.CLOSE);
shell.setSize(
new
Point(
400
,
400
));
shell.setLayout(
new
FillLayout());
shell.setText(
"
SWT半透明窗體實現
"
);
//
打開shell
shell.open();
//
設置窗體透明
OS.SetWindowLong(shell.handle,OS.GWL_EXSTYLE,OS.GetWindowLong(
shell.handle,OS.GWL_EXSTYLE)
^
0x80000
);
//
loadUser32.dlllib
TCHARlpLibFileName
=
new
TCHAR(
0
,
"
User32.dll
"
,
true
);
int
hInst
=
OS.LoadLibrary(lpLibFileName);
if
(hInst
!=
0
)
{
//
設定調用函數名稱
Stringname
=
"
SetLayeredWindowAttributes?
"
;
byte
[]lpProcName
=
new
byte
[name.length()];
for
(
int
i
=
0
;i
<
lpProcName.length;i
++
)
{
lpProcName[i]
=
(
byte
)name.charAt(i);
}
//
檢索DLL輸出函數地址
int
fun
=
OS.GetProcAddress(hInst,lpProcName);
//
當函數存在
if
(fun
!=
0
)
{
//
150為透明度,在0-255之間
OS.CallWindowProc(fun,shell.handle,
0
,
150
,
2
);
}
//
釋放lib
OS.FreeLibrary(hInst);
while
(
!
shell.isDisposed())
{
if
(
!
display.readAndDispatch())
{
display.sleep();
}
}
}
}
}
效果如圖:
嗯,很簡單,很方便.
不過,似乎有個問題,這些反復出現的OS,不就是封裝的Win32 API嗎?那么,SWT由于依賴本地平臺能夠實現,那么Swing那種"畫"出來的界面可以實現嗎?答案是肯定的,事實上,沒有一種界面不是系統"畫"來的,只要能獲得窗體的hWnd,也就是句柄,任何窗體的操作都是張飛吃豆芽-小菜一碟罷了.
下面,我用AWT/Swing完成同樣的操作.
package
org.loon.framework.dll.test;
import
java.awt.Frame;
import
java.awt.event.WindowAdapter;
import
java.awt.event.WindowEvent;
import
javax.swing.JFrame;
import
org.loon.framework.dll.NativeLoader;
/**
*<p>Title:LoonFramework</p>
*<p>Description:AWT/SWing實現真窗體透明</p>
*<p>Copyright:Copyright(c)2007</p>
*<p>Company:LoonFramework</p>
*
@author
chenpeng
*@email:ceponline@yahoo.com.cn
*
@version
0.1
*/
public
class
TransTest
{
public
static
void
main(
final
String[]args)
{
//
助于SetLayeredWindowAttributes函數,
//
在Windows下,AWT/SWing要實現不規則窗體、半透明窗體是非常容易的
JFrameframe
=
new
JFrame(
"
透明窗體測試
"
);
//
Frameframe=newFrame("透明窗體測試");
/*
frame.addWindowListener(newWindowAdapter(){
publicvoidwindowClosing(WindowEventwe){
System.exit(0);
}
});
*/
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(
true
);
//
NativeLoader為制作好的本地API集合,0.6f為透明度60%顯示
NativeLoader.getInstance().setTransparence(frame,
0.6f
);
frame.setSize(
400
,
400
);
frame.setLocationRelativeTo(
null
);
}
}
效果圖:
事實上,我們只要在 NativeLoader 中通過當前object在jawt.dll中的運行時hWnd,(即AWT窗體的hWnd,因為Swing底層是AWT,兩者一至),與SWT是沒有任何區別的.
再比如在AWT/Swing中,似乎很難實現真正的不規則窗體,充其量只能做一些"偽不規則窗體",而SWT借助本地支持卻能輕易實現.
AWT/Swing與SWT不規則窗體實現的比較:
比如SWT實現不規則窗體.
package
org.loon.framework.dll.test;
import
org.eclipse.swt.SWT;
import
org.eclipse.swt.graphics.Image;
import
org.eclipse.swt.graphics.ImageData;
import
org.eclipse.swt.graphics.Point;
import
org.eclipse.swt.graphics.Region;
import
org.eclipse.swt.widgets.Display;
import
org.eclipse.swt.widgets.Event;
import
org.eclipse.swt.widgets.Listener;
import
org.eclipse.swt.widgets.Shell;
/**
*<p>
*Title:LoonFramework
*</p>
*<p>
*Description:
*</p>
*<p>
*Copyright:Copyright(c)2007
*</p>
*<p>
*Company:LoonFramework
*</p>
*
*
@author
chenpeng
*@email:ceponline@yahoo.com.cn
*
@version
0.1
*/
public
class
SWTWindowFrm
{
private
Shellshell;
private
Displaydisplay
=
Display.getDefault();
private
Imageimage
=
null
;
private
ImageDataimageData
=
null
;
public
static
void
main(String[]args)
{
try
{
SWTWindowFrmwindow
=
new
SWTWindowFrm();
window.open();
}
catch
(Exceptione)
{
e.printStackTrace();
}
}
public
void
open()
{
createUI();
shell.open();
shell.layout();
while
(
!
shell.isDisposed())
{
if
(
!
display.readAndDispatch())
display.sleep();
}
}
protected
void
createUI()
{
shell
=
new
Shell(display,SWT.NO_TRIM);
shell.setSize(
500
,
375
);
shell.setText(
"
SWT實現不規則窗體
"
);
createShell();
Listenerlistener
=
new
Listener()
{
int
startX,startY;
public
void
handleEvent(Evente)
{
//
注入鼠標事件
if
(e.type
==
SWT.MouseDown
&&
e.button
==
1
)
{
startX
=
e.x;
startY
=
e.y;
}
if
(e.type
==
SWT.MouseMove
&&
(e.stateMask
&
SWT.BUTTON1)
!=
0
)
{
Pointp
=
shell.toDisplay(e.x,e.y);
p.x
-=
startX;
p.y
-=
startY;
shell.setLocation(p);
}
if
(e.type
==
SWT.Paint)
{
e.gc.drawImage(image,imageData.x,imageData.y);
}
}
}
;
shell.addListener(SWT.KeyDown,listener);
shell.addListener(SWT.MouseDown,listener);
shell.addListener(SWT.MouseMove,listener);
shell.addListener(SWT.Paint,listener);
}
protected
void
createShell()
{
Stringpath
=
this
.getClass().getResource(
"
role.gif
"
).getPath();
image
=
new
Image(display,
new
ImageData(path));
Regionregion
=
new
Region();
imageData
=
image.getImageData();
//
將255(白色)定為透明區域,鏤空
if
(imageData.alphaData
!=
null
)
{
for
(
int
y
=
0
;y
<
imageData.height;y
++
)
{
for
(
int
x
=
0
;x
<
imageData.width;x
++
)
{
if
(imageData.getAlpha(x,y)
==
255
)
{
region.add(imageData.x
+
x,imageData.y
+
y,
1
,
1
);
}
}
}
}
else
{
ImageDatamask
=
imageData.getTransparencyMask();
for
(
int
y
=
0
;y
<
mask.height;y
++
)
{
for
(
int
x
=
0
;x
<
mask.width;x
++
)
{
if
(mask.getPixel(x,y)
!=
0
)
{
region.add(imageData.x
+
x,imageData.y
+
y,
1
,
1
);
}
}
}
}
shell.setRegion(region);
shell.setSize(imageData.x
+
imageData.width,imageData.y
+
imageData.height);
}
}
效果圖如下:
但是,AWT/Swing做不到嗎?我已經說過了,只要能得到句柄,就沒有修改不了的窗體存在.而AWT/Swing顯然是可以得到運行時本地句柄的.
下面來個AWT/Swing實現:
package
org.loon.framework.dll.test;
import
java.awt.Image;
import
java.awt.Point;
import
java.awt.Window;
import
java.awt.event.FocusEvent;
import
java.awt.event.FocusListener;
import
java.awt.event.MouseEvent;
import
java.awt.event.MouseMotionListener;
import
java.awt.image.BufferedImage;
import
java.io.File;
import
java.io.IOException;
import
javax.imageio.ImageIO;
import
org.loon.framework.dll.win32.UIWindow;
/**
*<p>
*Title:LoonFramework
*</p>
*<p>
*Description:
*</p>
*<p>
*Copyright:Copyright(c)2007
*</p>
*<p>
*Company:LoonFramework
*</p>
*
*
@author
chenpeng
*@email:ceponline@yahoo.com.cn
*
@version
0.1
*/
//
UIWindow為本人提供類,內部已設置255為鏤空色
public
class
MyJWindow
extends
UIWindow
implements
MouseMotionListener,
FocusListener
{
private
static
final
long
serialVersionUID
=
1L
;
PointmousePointer;
public
MyJWindow(Imageimg)
{
super
(img);
init();
}
public
void
init()
{
addMouseMotionListener(
this
);
addFocusListener(
this
);
}
public
void
focusGained(FocusEventaFocusEvent)
{
PointaPoint
=
getLocation();
setLocation(
15000
,
0
);
setLocation(aPoint);
}
public
void
focusLost(FocusEventaFocusEvent)
{
}
public
void
mouseDragged(MouseEventaMouseEvent)
{
PointaPoint
=
aMouseEvent.getPoint();
int
x
=
getX()
+
aPoint.x
-
mousePointer.x;
int
y
=
getY()
+
aPoint.y
-
mousePointer.y;
setLocation(x,y);
}
public
void
mouseMoved(MouseEventaMouseEvent)
{
mousePointer
=
aMouseEvent.getPoint();
}
public
static
void
main(String[]args)
{
Stringpath
=
MyJWindow.
class
.getResource(
"
role.gif
"
).getPath();
BufferedImagebackgroundImage
=
null
;
try
{
backgroundImage
=
ImageIO.read(
new
File(path));
}
catch
(IOExceptione)
{
e.printStackTrace();
}
Windowwindow
=
new
MyJWindow(backgroundImage);
window.setBounds(
0
,
0
,backgroundImage.getWidth(
null
),backgroundImage
.getHeight(
null
));
window.setLocationRelativeTo(
null
);
window.setVisible(
true
);
window.validate();
}
}
效果如下圖:
兩者有區別嗎?
我們可以從此得知,不,可以說確信,在同樣利用本地API時,SWT與AWT/Swing相比是沒有太大優勢的.而且Sun已經開始優化AWT對本地系統的支持,再不久的將來,SWT可能將沒有任何優勢可言了^^ (我是親Sun一派~)
其中org.loon.framework.dll包下載路徑位于: loonframework-dll
于是,有一群人開始走向了邪路……
這群誤入岐途的人(至少Sun是這么認為的……),走出了自己的一條路,名為SWT(Standard Widget Toolkit)的不歸路(Sun,Sun|||)。
說起SWT冒著被詬病為邪惡所換取的,無外以下幾點:
1.徹底摒棄了AWT/Swing,某種意義上甚至架空了JVM,比如其通過dispose()即時釋放資源。(當然,大家也都知道這意味著什么)
2.功能幾乎全用本地系統完成,所以其界面與本地程序界面也高度一致,一改Java GUI的沉悶,令人眼前一亮。
3.支持本地API調用,也就是說無論本地系統能實現什么,都可以通過SWT照樣實現出來。
4.使用"用戶線程"作為唯一線程,只有在這個線程中才能調用對構件或某些圖形API的訪問操作,減少圖形操作時線程錯誤。但也允許間接的在非用戶線程的進行圖形構件的訪問操作。
5.在Windows下運行速度有保證,明顯超越AWT/Swing,且較穩定。
6.目前已有較豐富的組件庫,有JFace等輔助項目,借助于IDE之利,開發GUI程序速度N快……
但是,只所以被稱為邪道,也不是空穴來風,它的缺陷也是顯而易見的,比如:
1.JNI調用耗費的時間是不能忽略的。JNI調用速度要比普通Java方法調用慢好幾倍甚至幾十倍。即便是在Java 6中,這種情況并沒有改善。且Swing絕大部分是用Java平臺模擬出的組件,這個過程都在一個系統平臺內完成。而SWT是部分在本地系統完成,部分在Java平臺完成,進行操作時要在這兩個平臺之間需要進行頻繁的數據交互。SWT并沒有從根本上解決效率問題。
2.Swing可以享受JVM的特殊待遇,進行特殊優化,比如inline,JIT代碼,Swing事件隊列對于事件的預處理(合并Paint事件,批處理Java 2D光柵指令等),這就像本地組件可以利用操作系統進行優化一樣。而SWT由于采用本地操作,無法完成。
3.SWT只能自頂向下地構建GUI。因此,如果沒有父容器,子控件也就不存在,父容器無法在以后任意改變。不如AWT/Swing靈活。
4.在目前來講,SWT還是一個有限的圖形環境(Sun,依舊是Sun)。到目前為止,它對于Java2D和Java3D的支持還不怎么好。
5.SWT在Windows下速度雖快,是占了Microsoft提供的大量API之利,在其他平臺上則持平或較慢于AWT/Swing。
6.與AWT/Swing不同,SWT和JFace并不是Java技術的標準配置,需要在將JAR文件放到Java CLASSPATH中,并將DLL文件放到系統PATH中才能運行,較AWT/Swing更繁瑣,如果某天Sun大神發威,和標準JRE兼容都可能成為問題。
兩種論調勢成水火,各不相下,似乎都要徹底壓到另一方才可罷休。
其實我認為大可不必,使用何種技術,大體上只有開發人員才會關心,技術外的那些才是用戶所關心的。開發人員間再怎么爭辯,其實在外人眼里都是無意義的窩里斗罷了。
比如,SWT可以包含AWT/Swing,而在AWT/Swing下,要實現SWT的功能也是輕而易舉的。
我舉幾個程序的例子。
AWT/Swing與SWT透明窗體實現的比較:
在SWT中,由于高度集成本地環境,能夠完成很多AWT/Swing力所不能及,很Cool的工作,比如半透明的窗體,代碼如下:















































































效果如圖:

嗯,很簡單,很方便.
不過,似乎有個問題,這些反復出現的OS,不就是封裝的Win32 API嗎?那么,SWT由于依賴本地平臺能夠實現,那么Swing那種"畫"出來的界面可以實現嗎?答案是肯定的,事實上,沒有一種界面不是系統"畫"來的,只要能獲得窗體的hWnd,也就是句柄,任何窗體的操作都是張飛吃豆芽-小菜一碟罷了.
下面,我用AWT/Swing完成同樣的操作.












































效果圖:

事實上,我們只要在 NativeLoader 中通過當前object在jawt.dll中的運行時hWnd,(即AWT窗體的hWnd,因為Swing底層是AWT,兩者一至),與SWT是沒有任何區別的.
再比如在AWT/Swing中,似乎很難實現真正的不規則窗體,充其量只能做一些"偽不規則窗體",而SWT借助本地支持卻能輕易實現.
AWT/Swing與SWT不規則窗體實現的比較:
比如SWT實現不規則窗體.





























































































































效果圖如下:

但是,AWT/Swing做不到嗎?我已經說過了,只要能得到句柄,就沒有修改不了的窗體存在.而AWT/Swing顯然是可以得到運行時本地句柄的.
下面來個AWT/Swing實現:

































































































效果如下圖:

兩者有區別嗎?
我們可以從此得知,不,可以說確信,在同樣利用本地API時,SWT與AWT/Swing相比是沒有太大優勢的.而且Sun已經開始優化AWT對本地系統的支持,再不久的將來,SWT可能將沒有任何優勢可言了^^ (我是親Sun一派~)
其中org.loon.framework.dll包下載路徑位于: loonframework-dll
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
