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

为嵌入在另一个控件中的动态创建的控件定义自定义事件处理程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.09/5 (17投票s)

2006年1月13日

2分钟阅读

viewsIcon

66284

downloadIcon

1213

一种捕获命令消息并将其发送到任何窗口的简单方法。

概述

消息映射机制是事件驱动编程的支柱。在MFC框架中,DECLARE_MESSAGE_MAP(), BEGIN_MESSAGE_MAP()END_MESSAGE_MAP() 是创建消息路线图的三个宏。请参考MSDN文章以更好地理解这三个宏内部发生的事情。有了这个理解,编写一个用于嵌入在其他控件中的控件的自定义消息处理程序将非常简单。

我选择了一个基于对话框的MFC应用程序来演示这一点。插入一个MSHFlexGrid控件后,我在flex网格的单元格中添加了按钮和复选框。在我的示例应用程序中,按钮单击 (BN_CLICKED) 事件已被捕获,但您可以按照以下步骤轻松添加其他事件。

在基于对话框的MFC应用程序中,如果插入一个Microsoft Hierarchical Flex Grid控件,框架将自动添加包装类以调用控件类的公共方法。现在,如果我们希望在flex网格的第零列的每一行中插入按钮,这些按钮将在运行时显示,我们必须在对话框类的 OnInitDialog() 函数中插入以下代码。在此之前,将两个 CButton 指针作为主对话框类(即我们的示例中的 CDynMsgMapDlg 类)的私有数据成员添加(CButton *m_pCheckBox, *m_pButtons)。

OnInitDialog()

BOOL CDynMsgMapDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    ..............................
    ..............................
    // TODO: Add extra initialization here

    // Get Number of Rows of FlexGrid
    int nRow = m_hflexgrid.GetRows();

    // Create Button and CheckBox objects
    m_pButtons  = new CButton[m_hflexgrid.GetRows()];
    m_pCheckBox = new CButton[m_hflexgrid.GetRows()];

    for(int iCnt = 1; iCnt<nRow; iCnt++)
    {
        // Get Coordinates and Width,Height of flexgrid cells
        int nY     = m_hflexgrid.GetRowPos(iCnt);
        int nH     = m_hflexgrid.GetRowHeight(iCnt);
        
        // Get X-Coordinate and Width of flexgrid column number ZERO
        int nXBt = m_hflexgrid.GetColPos(0);
        int nWBt = m_hflexgrid.GetColWidth(0,0);

        // Get X-Coordinate and Width of flexgrid column number TWO
        int nXCb = m_hflexgrid.GetColPos(2);
        int nWCb = m_hflexgrid.GetColWidth(2,0);

        
        // Get the Grid Rectangle 
        CRect rectButton(nXBt/15, nY/15, (nXBt+nWBt)/15, (nY+nH)/15);
        // Get the Grid Rectangle 
        CRect rectCheckBox(nXCb/15, nY/15, (nXCb+nWCb)/15, (nY+nH)/15);

        CString cstrTextBt;
        cstrTextBt.Format("Button %d ",iCnt);
        // Create Button Dynamically Into the rectangle (Row=iCnt,Col=0)
        m_pButtons[iCnt].Create(
                     cstrTextBt, WS_CHILD|BS_PUSHBUTTON|WS_VISIBLE, 
                     rectButton, GetDlgItem(IDC_MSHFLEXGRID_TEST), 
                     iCnt+IDC_BUTTON_FIRST
                     );

        CString cstrTextCb;
        cstrTextCb.Format("CheckBox %d ",iCnt);
        // Create Button Dynamically Into the rectangle (Row=iCnt,Col=2)
        m_pCheckBox[iCnt].Create(
                     cstrTextCb, WS_CHILD|BS_AUTOCHECKBOX|WS_VISIBLE, 
                     rectCheckBox, GetDlgItem(IDC_MSHFLEXGRID_TEST), 
                     iCnt+IDC_CHECKBOX_FIRST
                      );

    }
    
    return TRUE;  // return TRUE  unless you set the focus to a control
}

这样,您将能够在网格的第零列和第二列中看到一个按钮和一个复选框数组。

现在,我们必须为已经创建的按钮添加一个点击事件处理程序。为此,您必须在 ClassWizard 生成的 BEGIN_MESSAGE_MAP()END_MESSAGE_MAP() 中添加宏 ON_CONTROL_RANGE()。这是我们的代码片段

BEGIN_MESSAGE_MAP(CDynMsgMapDlg, CDialog)
//{{AFX_MSG_MAP(CDynMsgMapDlg)
  ON_WM_SYSCOMMAND()
  ON_WM_PAINT()
  ON_WM_QUERYDRAGICON()
  ON_WM_DESTROY()
//}}AFX_MSG_MAP
ON_CONTROL_RANGE(BN_CLICKED,IDC_BUTTON_FIRST, 
            IDC_BUTTON_LAST, OnButtonClicked)
END_MESSAGE_MAP()

现在,在类声明中添加 OnButtonClicked() 原型。

afx_msg void OnButtonClicked(UINT nIDbutton);

OnButtonClicked() 的实现可能如下所示

void CDynMsgMapDlg::OnButtonClicked(UINT nIDbutton)
{
     MessageBox("BN_CLICKED Event trapped within  'MessageMap' Dialog");
}

执行完这些步骤后,如果我们尝试运行我们的应用程序,我们将看到一个消息框不会随着动态创建的按钮的点击事件而出现。其背后的原因是按钮的动态创建。由于按钮和复选框将 MSHFlexGrid 作为它们的父级,因此 BN_CLICKED 消息必须在 MSHFlexGrid 的包装类中被捕获。所以,添加 DECLARE_MESSAGE_MAP(), BEGIN_MESSAGE_MAP()END_MESSAGE_MAP() 以捕获 BN_CLICKED 事件,就像我们之前做的那样。现在,最后一件事是我们需要向 MSHFlexGrid 的父窗口(即主对话框窗口)发送一个 WM_COMMAND 消息,其 ID 相同。

BEGIN_MESSAGE_MAP(CMSHFlexGrid, CWnd)
    //{{AFX_MSG_MAP(CMSHFlexGrid)
    //}}AFX_MSG_MAP
    ON_CONTROL_RANGE(BN_CLICKED,IDC_BUTTON_FIRST, 
                IDC_BUTTON_LAST, OnButtonClicked)
END_MESSAGE_MAP()

// Button Click Event handler : Post this message as WM_COMMAND message
// to the parent window, i.e. the Dialog containing flexgrid
void CMSHFlexGrid::OnButtonClicked(UINT nID)
{
    GetParent()->SendMessage(
                                WM_COMMAND,
                                MAKELONG(nID,BN_CLICKED),
                                (LPARAM)(GetDlgItem(nID)->m_hWnd)
                            );
}

最后,使用 ClassWizard 添加 MSHFlexGrid 的 OnScroll() 事件,并在其中插入以下代码

void CDynMsgMapDlg::OnScrollMshflexgridTest() 
{
    // TODO: Add your control notification handler code here
    int nRow = m_hflexgrid.GetRows();
    int nTopRow = m_hflexgrid.GetTopRow();
    for(int iCnt = m_hflexgrid.GetFixedRows(); iCnt<nRow; iCnt++)
    {
        if(iCnt<nTopRow)
        {
            m_pButtons[iCnt].ShowWindow(SW_HIDE);
            m_pCheckBox[iCnt].ShowWindow(SW_HIDE);
        }
        else
        {
            // Get Coordinates and Width,Height of flexgrid cells
            int nY     = m_hflexgrid.GetRowPos(iCnt);
            int nH     = m_hflexgrid.GetRowHeight(iCnt);
            
            // Get X-Coordinate and Width of flexgrid column number ZERO
            int nXBt = m_hflexgrid.GetColPos(0);
            int nWBt = m_hflexgrid.GetColWidth(0,0);
            
            // Get X-Coordinate and Width of flexgrid column number TWO
            int nXCb = m_hflexgrid.GetColPos(2);
            int nWCb = m_hflexgrid.GetColWidth(2,0);
            
            
            // Get the Grid Rectangle 
            CRect rectButton(nXBt/15, nY/15, (nXBt+nWBt)/15, (nY+nH)/15);
            // Get the Grid Rectangle 
            CRect rectCheckBox(nXCb/15, nY/15, (nXCb+nWCb)/15, (nY+nH)/15);
            
            // Move Buttons and CheckBoxes along with the ScrollBar
            m_pButtons[iCnt].MoveWindow(rectButton);
            m_pButtons[iCnt].ShowWindow(SW_SHOW);
            m_pCheckBox[iCnt].MoveWindow(rectCheckBox);
            m_pCheckBox[iCnt].ShowWindow(SW_SHOW);
            
        }
    }    
}

现在,运行应用程序,单击网格内的按钮,您将看到您想要的。

我们需要注意这一点

  • 按钮和复选框的 ID 应该唯一。
© . All rights reserved.