?? jdk1.3 中的本地繪制支持.txt
字號:
JDK1.3 中的本地繪制支持
(加入日期:2001-5-6 點擊數:735)
【對此文發表評論】 【編程愛好者論壇】 【保存文章至硬盤】 【打印文章】
在 JDK1.3 出現以前,您僅能將 Java 本地接口用于非用戶界面的工作。JDK 1.3 引入了新的 Java 2 AWT 本地接口,這使您可以在 Java 程序中使用非 Java 的 GUI 組件,盡管這樣做會失去純 Java 解決方案的可移植性。在使用 J2AWT 時,您必須針對要使用它的每個平臺制作本地動態連接庫或共享庫。
下面這段話摘自 JDK1.3 的某個頭文件,它說明了這種新的 API 的開發背景及原因:
AWT 支持使用本地 C 或 C++ 應用程序訪問 AWT 的本地結構。這是為了便于將原有的 C 或 C++ 應用程序移植到 Java 并滿足需要 ... [這些應用程序] 出于性能方面的原因在畫布上自行進行本地繪制
在 JDK1.3 以前,Java 編程沒有明確的方法來訪問基層的同等 GUI 組件的句柄。在 JDK 1.3 中, Sun 公司創建了一種標準機制,通過這種機制,開發人員可以使本地 GUI 應用程序和庫在 Java AWT Canvas 對象中進行繪制。這意味著現在有一種正式的、有保證的方法來獲得支持這一功能的信息。當 JDK 1.3 與其他操作平臺對接時,所有的接口都提供相同的信息 -- 而不管使用的是什么系統。JDK 1.3 的 Windows 版本和 Solaris 版本是首先提供這種支持的實現。
Sun 公司引入這一功能組件有幾方面的原因。首先, JDK 1.3 使得人們可以將依賴第三方產品的復雜原有軟件移植到 Java 上,而不必等到第三方產品本身完成移植以后。第二個原因即性能;如果本地的 GUI 代碼經過人們長時期的努力得到優化,則原樣保留這些軟件具有重要的商業價值。
在本文中,我將介紹一些該功能部件的基本概念。我將逐步開發一個窗口小部件樣例,該窗口小部件使用Win32 API 進行繪制。下圖是最終的窗口小部件的快照,一個帶有笑臉的圓形窗口。
運行中的窗口小部件
分步概覽
第一步,定義一個 Java 類 -- 比如說,Mywindow -- 使其繼承 Canvas 類并重載 paint 方法。您使用 paint 方法執行 AWT 對象的繪制操作,并在覆蓋該方法時加上 native 關鍵字。覆蓋方法使您能夠使用自己的本地代碼。您必須構建自己的本地代碼并把它編譯成一個動態連接庫,就像我們處理其他的 Java 本地接口應用程序一樣,在本例中,我們將調用 MyWindow.DLL 庫。在 Solaris 和 Linux 上則為共享對象或共享庫。您還需要用 System.loadLibrary("MyWindow") 調用將 MyWindow.DLL 庫加載到您的名為 MyWindow 的 Java 類中。
完成這一示例需要二個部分:其一是 MyWindow.Java ,它提供 Canvas 類的子類,其二是 MyWindow.CPP ,它包含基于 Java 本地接口的繪制子程序的入口點。 在參考資源部分可找到 MyWindow.Java、MyWindow.CPP 及自動執行編譯的批處理文件 BUILD.BAT。
第一步: 創建 MyWindow Java 類
J2AWT 用于這種方法時有一個主要的局限性:本地代碼只能對 java.awt.Canvas 類的子類進行操作。這正是 MyWindow 繼承 Canvas 類的原因。在 Java 應用程序中,您可以像使用 Canvas 的其它子類那樣使用 MyWindow;在本例中,我將 MyWindow 添加到 Jwindow 中。
import java.awt.*;
import javax.swing.*;
public class MyWindow extends Canvas {
static {
//加載包含 paint 代碼的庫。
System.loadLibrary("MyWindow");
}
//繪制操作的本地入口點
public native void paint(Graphics g);
public static void main( String[] argv ){
Frame f = new Frame();
f.setSize(300,400);
JWindow w = new JWindow(f);
w.setBackground(new Color(0,0,0,255));
w.getContentPane().setBackground(new Color(0,0,0,255));
w.getContentPane().add(new MyWindow());
w.setBounds(300,300,300,300);
w.setVisible(true);
}
}
請注意:您是在靜態塊中加載 MyWindow.DLL。這正是 Java 應用程序訪問本地代碼的方式。(我稍候就會開發這段本地代碼。)同時還應注意:paint 方法是用 native 關鍵字聲明的,并且沒有提供任何實現;這樣做是為了讓虛擬機知道,應該從在靜態塊中加載的動態連接庫中調用該本地方法。
第二步:生成該類的 JNI 頭文件
要為以上定義的類生成 Java 本地接口頭文件,需使用 javah MyWindow.class 命令。首先應確保這個類文件在您的 CLASSPATH 中。以下是所生成的 MyWindow.h 的一部分,給出了函數聲明。
/*
* Class: MyWindow
* Method: paint
* Signature: (Ljava/awt/Graphics;)V
*/
JNIEXPORT void JNICALL Java_MyWindow_paint
(JNIEnv *, jobject, jobject);
第三步:開發完整的 MyWindow.CPP
以下是完整的 MyWindow.CPP,其中包含 MyWindow.Java 中所需要的繪圖程序的本地代碼。
#include <windows.h>
#include <assert.h>
#include "jawt_md.h"
#include "MyWindow.h"
#define X(x) (int)(xLeft + (x)*xScale/100) // 縮放宏
#define Y(y) (int)(yTop + (y)*yScale/100) // 以使尺度在 0-100 之間
#define CX(x) (int)((x)*xScale/100)
#define CY(y) (int)((y)*yScale/100)
void DrawSmiley(HWND hWnd, HDC hdc);
HRGN hrgn = NULL;
JNIEXPORT void JNICALL
Java_MyWindow_paint(JNIEnv* env, jobject canvas, jobject graphics)
{
JAWT awt;
JAWT_DrawingSurface* ds;
JAWT_DrawingSurfaceInfo* dsi;
JAWT_Win32DrawingSurfaceInfo* dsi_win;
jboolean result;
jint lock;
// 獲取 AWT
awt.version = JAWT_VERSION_1_3;
result = JAWT_GetAWT(env, &awt);
assert(result != JNI_FALSE);
// 獲取繪圖界面
ds = awt.GetDrawingSurface(env, canvas);
if(ds == NULL)
return;
// 鎖定繪圖表面
lock = ds->Lock(ds);
assert((lock & JAWT_LOCK_ERROR) == 0);
// 獲取繪圖表面的信息
dsi = ds->GetDrawingSurfaceInfo(ds);
// 獲取特定平臺的繪圖信息
dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
HDC hdc = dsi_win->hdc;
HWND hWnd = dsi_win->hwnd;
//////////////////////////////
// !!! 在此處進行繪圖 !!! //
//////////////////////////////
if(hrgn == NULL)
{
RECT rcBounds;
GetWindowRect(hWnd,&rcBounds);
long xLeft = 0; // 用于縮放宏
long yTop = 0;
long xScale = rcBounds.right-rcBounds.left;
long yScale = rcBounds.bottom-rcBounds.top;
hrgn = CreateEllipticRgn(X(10), Y(15), X(90), Y(95));
SetWindowRgn(GetParent(hWnd),hrgn,TRUE);
InvalidateRect(hWnd,NULL,TRUE);
} else {
DrawSmiley(hWnd,hdc);
}
// 釋放繪圖表面的信息
ds->FreeDrawingSurfaceInfo(dsi);
// 為繪圖表面解鎖
ds->Unlock(ds);
// 釋放繪圖表面
awt.FreeDrawingSurface(ds);
}
void DrawSmiley(HWND hWnd, HDC hdc)
{
RECT rcBounds;
GetWindowRect(hWnd,&rcBounds);
long xLeft = 0; // 用于縮放宏
long yTop = 0;
long xScale = rcBounds.right-rcBounds.left;
long yScale = rcBounds.bottom-rcBounds.top;
// 基于控制大小的畫筆寬度
int iPenWidth = max(CX(5), CY(5));
HBRUSH brushBlack;
HBRUSH brushYellow;
HPEN penBlack = CreatePen(PS_SOLID, iPenWidth, RGB(0x00,0x00,0x00));
// 用于繪制填充橢圓的空畫筆
HPEN penNull = CreatePen(PS_NULL, 0, (COLORREF)0);
brushBlack = CreateSolidBrush(RGB(0x00,0x00,0x00));
brushYellow = CreateSolidBrush(RGB(0xff,0xff,0x00));
HPEN pPenSave = (HPEN)SelectObject(hdc, penBlack);
HBRUSH pBrushSave = (HBRUSH)SelectObject(hdc,brushYellow);
Ellipse(hdc,X(10), Y(15), X(90), Y(95)); // 頭部
Arc(hdc,X(25), Y(10), X(75), Y(80), // 嘴部(微笑)
X(35), Y(70), X(65), Y(70));
SelectObject(hdc,&penNull); // 無繪圖寬度
SelectObject(hdc,&brushBlack);
Ellipse(hdc,X(57), Y(35), X(65), Y(50));
Ellipse(hdc,X(35), Y(35), X(43), Y(50)); // 右眼
Ellipse(hdc,X(46), Y(50), X(54), Y(65)); // 鼻子
SetBkMode(hdc,TRANSPARENT); // 使用前景顏色
SelectObject(hdc,pBrushSave);
SelectObject(hdc,pPenSave);
}
這里的關鍵數據結構是 JAWT,它是在 jawt.h 中定義的(通過 jawt_md.h 包含在內)。它使程序可以訪問本地代碼在基于 Java 的 GUI 組件上繪圖所需的所有信息。本地方法的第一部分是套式:置入 JAWT 結構,獲得一個 JAWT_Win32DrawingSurfaceInfo 結構,鎖定表面(請一次只使用一種繪圖工具!),然后,獲取一個 JAWT_DrawingSurfaceInfo 結構,該結構包含特定平臺下繪圖所必需的指針(在 platformInfo字段中)。它也包含繪圖界面的矩形界限框及當前剪切區域。有關詳細信息,請查看 jawt.h 和 jawt_md.h (請參閱下面標題為 “構建環境”的部分)。
Java_MyWindow_paint 是一個入口點,JVM 通過調用它來繪制 MyWindow。輔助函數 DrawSmiley 使用 Win32 調用來完成實際的繪制工作。要在您的應用程序中包含 GetDrawingSurfaceInfo,請使用外部庫 jawt.lib(請參閱 “構建環境”)。
第四步:編輯 BUILD.BAT
在運行 BUILD.BAT 之前首先對它進行編輯,并像如下所示的那樣,為您的 Visual C++ 及 JDK1.3 設置路徑。BUILD.BAT 對 MyWindow.java 進行編譯,生成 MyWindow.h,然后將 MyWindow.CPP 編譯為 MyWindow.DLL。
SET DEVSTUDIO=D:\Program Files\Microsoft Visual Studio\VC98
SET JDK13=D:\JDK1.3
好了,一切準備就緒。在運行該樣例之前,請確保 MyWindow.DLL、\JDK1.3\BIN 及 \JDK1.3\JRE\BIN 都在 PATH 內,還要保證當前目錄在 CLASSPATH 中;這將確保 MyWindow.class 會被成功加載。在確信 PATH 和 CLASSPATH 都設置妥當后,在命令行輸入 java MyWindow 來運行此應用程序。為方便您的使用,window.zip 中包含了一個批處理文件 RUN.BAT(請參閱參考資源)。要為 JDK 1.3 設置PATH 和 CLASSPATH,請編輯 RUN.BAT。
構建環境
頭文件:在 JDK 的 include 目錄中新增了專用于 Windows 的 C 頭文件。它們是:
include/jawt.h.
include/win32/jawt_md.h.
依據 JavaSoft 網站的說明,這些頭文件并不是 Java 2 平臺正式規范的組成部分;提供這些頭文件只是為希望用一種標準化方法訪問本地繪圖功能的開發人員提供一種便利。我認為這表示將 JDK 移植到其它平臺的廠商可以不提供這個 API。
庫:一個以 jawt.lib 命名的新庫已添加到 SDK 的庫目錄中。如前所述,這個庫包含一個用于把 J2AWT 包含到您的應用程序中所需要的入口點。例如,要鏈接到 GetDrawingSurfaceInfo 入口點,您需要在您的程序中包含 jawt.lib。
工具:javah 工具用來為 Java 類的本地函數生成 C/C++ 頭文件,javac 工具用來編譯 Java 源文件。
小結
將原有軟件系統移植到 Java 中并不容易,尤其是當原有軟件包含高性能的繪圖器時。Java 2 AWT 本地接口使得分階段移植變得較為容易,它允許您首先移植對性能要求不高的代碼,然后再移植關鍵的繪制代碼。它同時使第三方窗口小部件開發廠商更能嚴肅地看待針對 Java 產品的開發。有了 Java 2 AWT 本地應用程序接口,您就可以移植原有的 GUI 代碼,并更快地完成開發,這樣就不會犧牲您為提高本地代碼關鍵部分的性能而作的投資。
本欄文章均來自于互聯網,版權歸原作者和各發布網站所有,本站收集這些文章僅供學習參考之用。任何人都不能將這些文章用于商業或者其他目的。( ProgramFan.Com )
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -