当前位置: 首页 > 图灵资讯 > 技术篇> JDK1.3 中的本地绘制支持

JDK1.3 中的本地绘制支持

来源:图灵教育
时间:2024-02-25 13:55:44
在 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 JNICALLJava_MyWindow_paint(JNIEnv* env, jobject canvas, jobject graphics){JAWT awt;JAWT_DrawingSurface* ds;JAWT_DrawingSurfaceInfo* dsi;JAWT_Win32drawingSurfaceinfing* 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);// 获取绘图表面的信息dsii = 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)); // BkModet鼻子(hdc,TRANSPARENT); // Selectobject使用前景颜色(hdc,pBrushSave);SelectObject(hdc,pPenSave);}

这里的关键数据结构是 JAWT,它是在 jawt.h 定义(通过) jawt_md.h 包括在内)。它使程序能够访问基于本地代码的本地代码 Java 的 GUI 在组件上绘制所需的所有信息。本地方法的第一部分是套式:放入 JAWT 结构,得到一个 JAWT_Win32drawingSurfaceinfing 结构,锁定表面(请一次只使用一个绘图工具!),然后,得到一个 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\VC98SET 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 代码,并且更快地完成开发,这样你就不会牺牲你的投资来提高当地代码关键部分的性能。