在 MFC 对话框中嵌入 JavaBean






4.56/5 (15投票s)
2004 年 3 月 6 日
4分钟阅读

50601

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_NCHITTEST
和 WM_GETDLGCODE
消息 (每秒!)。由于这种消息泛滥,CPU 使用率会增加到 100%,并且整个系统会挂起。
我的第一个假设是,这种效果与容器有关,在本例中是 CTabCtrl
。我决定始终将 CEmbeddedJFrame
嵌入 CDialog
中,使用 CDialog
作为中间层。但是,当我强制 CDialog
成为 CTabCtrl
的子窗口时,结果与系统死锁相同。
如果您想看到这种效果,请尝试将 CEmbeddedJFrame
嵌入 CTabCtrl
中。您可以在 MSVC 资源编辑器中轻松完成此操作。但要小心。当您使用 Spy++ 并在调试会话中启动应用程序时,您的系统可能会在 InitApplication()
开始时挂起。
欢迎就此话题提供任何形式的贡献。如果您对此有任何想法,请随时发表评论。
链接
历史
版本 1.0 - 在 Win2K/XP 上稳定,除了一个主要问题 (见上文)。