65.9K
CodeProject 正在变化。 阅读更多。
Home

在 MFC 对话框中嵌入 JavaBean

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (15投票s)

2004 年 3 月 6 日

4分钟阅读

viewsIcon

50601

downloadIcon

816

无需使用 Sun 的 ActiveX 桥即可嵌入 JavaBean。

引言

几周前,我一直在想 Sun 的 ActiveX 桥是如何将 JavaBeans 嵌入 MFC 对话框的。阅读了一些关于这个主题的新闻组文章后,我得出的结论是,通过 MFC 将自己的 JavaBean 嵌入对话框并没有真正可用的示例。因此,我决定编写自己的 JavaBridge,这是我努力的成果。

但首先,请原谅我在英语写作或本文结构上的任何错误,因为这是我写的第一篇 CodeProject 文章。

使用代码

在运行示例项目之前,请确保您的计算机上已正确安装 Java 软件开发工具包 (SDK) 版本 1.4.2 或更高版本。您可以在此处获取 SDK。

另请注意,`JAVA_HOME` 环境变量已设置为您系统上的相应目录。

我使用Java 本地接口 (或调用接口) 来加载 Java 虚拟机并实例化 JavaBean。为了更好地理解,我将类分为两组。第一组由涵盖 JNI 问题的类组成。您会在子文件夹 JBridge 中找到它们。不要过多关注这些类,因为本文无意介绍 JNI。您可以在网上找到关于该主题的适当文献 (参见下文的链接)。

另一组类涵盖 MFC 问题。特别是 CEmbeddedJFrame 将是我们的主要关注点。

当您启动应用程序时,将创建一个 CEmbeddedJFrame 实例,并且 `init()` 成员函数将从 CGUIBeanDlg::OnInitDialog() 中调用。

我的想法是创建一个 JavaBean,将其嵌入 JFrame 实例,然后将此框架对象作为对话框的子窗口。下面的代码片段显示了实现此功能的位置。

Java VM 和 bean 在第 9 行加载。如您所见,bean 是由一个名为 bean.jar 的 Java 存档文件提供的。您可以在项目工作目录的 bean 子目录中找到此文件。实例化 bean 后,将创建 JFrame 对象。由于我不想让您费心于 JNI 细节,因此我在 JBridge 子文件夹的 JFrame 类中封装了适当的 JNI 调用。在框架首次显示之前,将 bean 实例添加到该框架的内容窗格中 (参见第 23 行)。

为了使框架成为对话框的子窗口,获取其 HWND 至关重要。有两种方法 (我最好说:我所知道的两种方法) 可以从本机应用程序获取 Java 对象的 HWND。第一种方法是使用 JNI 获取指向 JAWT 接口的指针。此接口提供了一些用于获取图形对象 (如 JFrame) 的绘图表面的函数。您可以从该绘图表面识别 HWND。但在我实现这一点时,它是一个非常不稳定且容易出错的解决方案。因此,我决定采用一种比较“粗暴”的方式,通过搜索框架的适当标题来获取 HWND。这在 Attach_JavaFrame() 操作中完成。

1  void CEmbeddedJFrame::init()
2  {
3    TCHAR szExePath[MAX_PATH];
4    GetModuleFileName(AfxGetInstanceHandle(), szExePath, MAX_PATH);
5    CString beanjar = szExePath;
6    beanjar = beanjar.Left(beanjar.ReverseFind('\\') + 1) + "bean\\bean.jar";
7
8    //JavaBean laden
9    theAdapter.initf(beanjar, "codeproject", "Editor");
10    JNIEnv *env = theAdapter.getJVMLoader()->getENV();
11
12
13    srand((unsigned)time(NULL));
14    CString title;
15    title.Format("bean_Editor_%d%d", rand(), rand());
16
17    //JFrame-Instanz erzeugen
18    frame = new JFrame((const char*)title);
19
20    frame->setBounds(-100,-100,0,0);
21    frame->show();
22    frame->setVisible(JNI_FALSE);
23    frame->add(theAdapter.getBeanInstance());
24
25    //Nun das JFrame-Objekt zum Child-Window machen
26    Attach_JavaFrame((const char*)title);
27
28    dockundock();
29
30    //Hier wieder einschalten
31    frame->setVisible(JNI_TRUE);
32 }

最后,通过设置 WS_CHILDWINDOW 样式和正确的父窗口,使此 Java 框架成为对话框的子窗口。请仔细查看 dockundock() 成员函数。

已知错误 (欢迎您提供帮助 ;) )

在此示例中,JavaBean 直接嵌入对话框中,一切正常。但如果您将 CEmbeddedJFrame 放入 CTabCtrl 中,那么 AWT 会向该容器发送大量 WM_NCHITTESTWM_GETDLGCODE 消息 (每秒!)。由于这种消息泛滥,CPU 使用率会增加到 100%,并且整个系统会挂起。

我的第一个假设是,这种效果与容器有关,在本例中是 CTabCtrl。我决定始终将 CEmbeddedJFrame 嵌入 CDialog 中,使用 CDialog 作为中间层。但是,当我强制 CDialog 成为 CTabCtrl 的子窗口时,结果与系统死锁相同。

如果您想看到这种效果,请尝试将 CEmbeddedJFrame 嵌入 CTabCtrl 中。您可以在 MSVC 资源编辑器中轻松完成此操作。但要小心。当您使用 Spy++ 并在调试会话中启动应用程序时,您的系统可能会在 InitApplication() 开始时挂起。

欢迎就此话题提供任何形式的贡献。如果您对此有任何想法,请随时发表评论。

链接

历史

版本 1.0 - 在 Win2K/XP 上稳定,除了一个主要问题 (见上文)。

© . All rights reserved.