睿诚科技协会

ActiveX控件中如何引入窗体技术?

为什么要在 ActiveX 控件中使用窗体?

想象一个场景:你正在开发一个 ActiveX 控件,用于配置一个复杂的图表,如果直接在控件的表面放置几十个配置选项(如坐标轴、图例、数据系列等),会使得控件界面臃肿不堪,并且难以管理。

ActiveX控件中如何引入窗体技术?-图1
(图片来源网络,侵删)

更好的方法是:

  1. 控件本身只显示一个简单的图表或一个“设置”按钮。
  2. 当用户点击“设置”按钮时,弹出一个独立的窗体(对话框)。
  3. 这个对话框窗体包含了所有复杂的配置选项。
  4. 用户在对话框中进行设置,点击“确定”后,对话框关闭,并将设置结果传递回 ActiveX 控件,控件根据新设置重新绘制自身。

这样做的好处显而易见:

  • 界面清晰:控件保持简洁,复杂的配置逻辑被封装在对话框中。
  • 代码解耦:控件的绘制代码和配置对话框的界面/逻辑代码分离,便于维护。
  • 功能强大:可以利用窗体的所有功能,如菜单、工具栏、多页面等。

核心原理:控件与窗体的通信

实现这一功能的核心在于建立 ActiveX 控件对话框窗体 之间的双向通信。

  1. 控件 -> 窗体 (单向)

    ActiveX控件中如何引入窗体技术?-图2
    (图片来源网络,侵删)
    • 时机:当控件需要显示窗体时(响应按钮点击事件)。
    • 方式:控件创建一个对话框窗体的实例,并可能需要向窗体传递一些初始数据,将当前的配置状态传递给对话框,以便对话框在打开时显示当前的设置。
  2. 窗体 -> 控件 (单向)

    • 时机:当用户在对话框中点击“确定”或“应用”按钮,并关闭对话框时。
    • 方式:对话框需要将用户在界面上修改的新数据“返回”给控件,这通常通过以下两种方式实现:
      • 方式一(推荐):通过对话框类的成员变量,这是最标准、最清晰的方式,对话框类定义成员变量来绑定到对话框上的控件(如编辑框、复选框),当用户点击“确定”时,这些成员变量中就保存了最新的值,控件在创建对话框时,将自己的数据设置到对话框的成员变量中;在对话框关闭后,再从这些成员变量中读取新数据。
      • 通过控件的公共方法,对话框可以调用 ActiveX 控件暴露给外部(宿主程序,如 VB, C# 或网页)的公共方法来传递数据,控件可以定义一个 ApplySettings(newSettings) 方法,对话框在关闭前调用这个方法。

详细实现步骤 (以 MFC ActiveX 控件为例)

假设我们要创建一个名为 MyDialogCtrl 的 ActiveX 控件,它包含一个按钮,点击后弹出 MySettingsDialog 对话框。

步骤 1:创建对话框资源

  1. 在你的 MFC ActiveX 控件工程中,插入一个新的对话框资源。
  2. 使用 Resource View -> 右键点击 Dialog -> Insert Dialog...
  3. 设计你的对话框界面,添加所需的控件(如编辑框、复选框、列表框等)。
  4. 为对话框资源创建一个类:
    • 双击对话框资源,或者右键点击对话框 -> Add Class...
    • 选择 MFC Class,点击“Add”。
    • 为类命名,CMySettingsDialog,并确保基类是 CDialogEx
    • 关键步骤:为对话框上的每个控件(ID 为 IDC_EDIT_NAME 的编辑框)添加 成员变量,在“Add Member Variable”向导中,选择“Value”类型,并指定变量类型(如 CString)和变量名(如 m_strName),这些变量将用于在控件和对话框之间传递数据。

步骤 2:在 ActiveX 控件类中添加成员变量和方法

  1. 添加成员变量:在你的控件类(CMyDialogCtrl)的头文件(.h)中,添加两个成员变量:

    • 一个用于存储当前配置的数据结构(或简单变量)。
    • 一个指向对话框对象的指针。
    // MyDialogCtrl.h
    class CMyDialogCtrl : public COleControl
    {
        // ... 其他代码
    public:
        // ... 其他方法
        // 对话框指针
        CMySettingsDialog* m_pSettingsDialog;
        // 存储配置数据的成员变量
        CString m_strCurrentName;
        BOOL m_bIsEnabled;
    protected:
        // ... 其他代码
    };
  2. 添加方法:在控件类中添加一个公共方法,用于触发显示对话框,这个方法通常被控件的某个事件(如按钮点击)调用。

    ActiveX控件中如何引入窗体技术?-图3
    (图片来源网络,侵删)
    // MyDialogCtrl.h
    class CMyDialogCtrl : public COleControl
    {
        // ...
    public:
        // ... 其他方法
        // 声明一个公共方法来显示对话框
        void ShowSettingsDialog();
        // ...
    };

步骤 3:实现控件逻辑

  1. 初始化:在控件类的构造函数中,将对话框指针初始化为 NULL

    // MyDialogCtrl.cpp
    CMyDialogCtrl::CMyDialogCtrl() : m_pSettingsDialog(NULL)
    {
        // TODO: 初始化成员变量
        m_strCurrentName = _T("Default Name");
        m_bIsEnabled = TRUE;
    }
  2. 实现 ShowSettingsDialog 方法:这是核心部分,我们将创建对话框、传递数据、显示对话框,并在关闭后获取新数据。

    // MyDialogCtrl.cpp
    #include "MySettingsDialog.h" // 确保包含对话框类的头文件
    void CMyDialogCtrl::ShowSettingsDialog()
    {
        // 1. 创建对话框对象
        // 注意:使用 new 创建,因为 DoModal 会阻塞,对象必须存在
        if (m_pSettingsDialog == NULL)
        {
            m_pSettingsDialog = new CMySettingsDialog();
        }
        // 2. 将控件的当前数据传递给对话框
        // 假设对话框类 CMySettingsDialog 有 SetInitialData 方法
        // 或者直接设置其成员变量
        m_pSettingsDialog->m_strName = m_strCurrentName;
        m_pSettingsDialog->m_bEnabled = m_bIsEnabled;
        // 3. 以模态方式显示对话框
        // DoModal 会阻塞,直到对话框关闭
        INT_PTR nResult = m_pSettingsDialog->DoModal();
        // 4. 对话框关闭后,检查用户点击的是“确定”还是“取消”
        if (nResult == IDOK)
        {
            // 用户点击了“确定”,从对话框中获取新数据
            m_strCurrentName = m_pSettingsDialog->m_strName;
            m_bIsEnabled = m_pSettingsDialog->m_bEnabled;
            // 5. (可选) 数据更新后,通知控件重绘或触发事件
            InvalidateControl(); // 使控件无效,导致 OnDraw 被调用
            FireClick();         // 假设你定义了一个 Click 事件来通知宿主
        }
        // 6. 清理对话框对象
        // 注意:对于模态对话框,DoModal 返回后会自动销毁窗口,
        // 但我们是用 new 创建的,所以需要手动 delete
        if (m_pSettingsDialog != NULL)
        {
            delete m_pSettingsDialog;
            m_pSettingsDialog = NULL;
        }
    }

步骤 4:将方法与控件事件关联

为了让宿主程序(如 VB6, C# 或网页中的 JavaScript)能够触发这个对话框,你需要将 ShowSettingsDialog 方法暴露出去。

  1. 添加方法到 .odl 文件:打开你的工程中的 .odl 文件(MyDialogCtrl.odl),在 dispinterface 中添加你的方法。

    // MyDialogCtrl.odl
    [
        uuid(...), // 你的控件 GUID
        helpstring("MyDialogCtrl 1.0 Type Library"),
        version(1.0)
    ]
    library MYDIALOGCTRLTLB
    {
        // ... 其他代码
        importlib("stdole2.tlb");
        [
            uuid(...), // 你的接口 GUID
            helpstring("_IMyDialogCtrlEvents")
        ]
        dispinterface _IMyDialogCtrlEvents
        {
            // ... 这里是事件,不是方法
        };
        [
分享:
扫描分享到社交APP
上一篇
下一篇