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

对话框通信

2007 年 2 月 26 日

CPOL

3分钟阅读

viewsIcon

76871

downloadIcon

850

关于数据交换的艺术

Screenshot - CommDlgs1.jpg Child modifying Parent modified

引言

我们经常需要从一个对话框与另一个对话框进行通信。我将以此为中心,使用两个经典的 MFC CDialog 继承类来演示,每个类都是模态的。

并且,由于我更倾向于先编写可运行的代码,然后再美化它,我将提供编写良好的代码,使读者更容易理解。请注意,我并不自诩编码完美,也没有遵循 THE 方法论。我只想给我的读者(主要是初学者)一个坚实的基础,让他们自己理解并编写代码。

不再多言,现在让我们进入代码。

起点:我感到孤独,我需要一个孩子

好的,这是一个相当遥远的需求起源。无论如何,我得到了这个机会来向您介绍这些角色。

CParentDlg:父对话框

CChildDlg:子对话框

class CParentDlg : public CDialog 
{
    CButton m_btnOpenChild;    
          //The button that will open the child dialog
    CEdit m_edtCommentText;  
          //Used to transmit a comment to the child
    CButton m_chkCaptainBlind; 
          //Same with a boolean to indicate if the captain is blind
 
public:
    CParentDlg();
 
protected:
    afx_msg void OnOpenChild();  
          //Even Handler of the m_btnOpenChild button click
};

class CChildDlg : public CDialog 
{
    CEdit   m_edtCommentText;    //The comment received
    CButton m_chkCaptainBlind;   //And the boolean received
    CString m_strComment;
    bool    m_bIsCaptainBlind;
 
public:
    CChildDlg(const CString& strComment, bool bIsCaptainBlind);
    const CString& GetComment() const;
    bool IsCaptainBlind() const;
 
protected:
    virtual BOOL OnInitDialog(); 
          //Used to initialize the controls before the dialog
          // is displayed at its first time afx_msg void OnOK();
    afx_msg void OnOK();         
          //Even  Handler of the OK button click
};

请注意,类声明已被简化,仅显示重要的点。因此,IDD 枚举器、DoDataExchange()OnQueryDragIcon()OnSysCommand()OnPaint()DECLARE_MESSAGE_MAP() 已实现但在此处隐藏。但是,我保留了 OnInitDialog(),因为它很快将扮演主要角色; 就像类构造函数一样。

现在,当按下父对话框上的按钮时,我们可以打开子对话框。

void CParentDlg::OnOpenChild() 
{
    CString strComment;
    m_edtCommentText.GetWindowText(strComment);
    bool bIsCaptainBlind = m_chkCaptainBlind.GetCheck();
 
    CChildDlg dlg(strComment, bIsCaptainBlind);
    INT_PTR nResponse = dlg.DoModal();
    if (nResponse == IDOK) 
    {
        m_edtCommentText.SetWindowText(dlg.GetComment());
        m_chkCaptainBlind.SetCheck(dlg.IsCaptainBlind());
    }
}

简而言之,该函数首先获取 EditBox 的内容和 CheckBox 的状态。一旦收集了这些信息,我们就将它们传递给子对话框并显示它。现在,子对话框负责数据的完整性。在我们的例子中,父对话框将获得这些值,因为子对话框选择了“确定”,否则,什么都不做。

哦,亲爱的宝贝,现在我们可以说话了

请注意上面 OnOpenChild() 函数中的两个重要行:调用子对话框的构造函数,以及使用 DoModal() 开始实际显示。

让我们详细说明这里发生了什么。

构造:提供信息

您肯定已经注意到了构造函数调用中的参数。以下是我们可以定义子对话框的方式

CChildDlg::CChildDlg(const CString& strComment, bool bIsCaptainBlind) 
{
    this->m_strComment = strComment;
    this->m_bIsCaptainBlind = bIsCaptainBlind;
}

现在,我们将数据存储在子对话框类中。但我们仍然需要正确显示它们。

显示:显示信息

我们不直接编写 DoModal() 函数。这个函数是从 CDialog 类继承而来的,我们不需要知道它做了什么,除了它构造一个模态对话框,在此过程中执行我们的 OnInitDialog()

BOOL CChildDlg::OnInitDialog() 
{
    CDialog::OnInitDialog();
    m_edtCommentText.SetWindowText(m_strComment);
    m_chkCaptainBlind.SetCheck(m_bIsCaptainBlind);
    return TRUE;
}

让用户玩,并在他离开时给我反馈

对我们(作为开发人员)来说,除了等待之外,没有什么可做的。

子对话框已被构造、初始化然后显示。用户现在正在使用 UI,修改我们的初始注释并选中/取消选中我们的 CheckBox。

可以添加一些事件处理程序,但这不是重点。我们只是涵盖父对话框与其子对话框之间的通信。

然后我们等待直到子对话框关闭。在这里,有两种可能性:通过“确定”验证更改,或取消(使用同名的按钮)。

在这里,我选择让用户更改他想要的内容,并且只有在按下“确定”后,这两个数据成员才会更新。为此,我在“确定”按钮上添加了一个事件处理程序。

void CChildDlg::OnOK() 
{
    m_edtCommentText.GetWindowText(m_strComment);
    m_bIsCaptainBlind = m_chkCaptainBlind.GetCheck();
    EndDialog(IDOK);
}

为什么我们需要这个?因为父对话框将使用 GetComment()IsCaptainBlind() 访问器来恢复这些成员的内容。

嘿,爸爸,这是你的数据

让我们跳回 OnOpenChild() 父处理程序的结尾

if (nResponse == IDOK) 
{
    m_edtCommentText.SetWindowText(dlg.GetComment());
    m_chkCaptainBlind.SetCheck(dlg.IsCaptainBlind());
}

当按下“确定”按钮时,我们现在进入 if 语句,并最终更新父 UI。

摘要

这是一个相当简单的例子。在现实世界中,您通常需要根据情况交换大量数据。

通常的做法是将所有需要交换的数据封装在一个为此定义的类中,并传递该类的单个实例。

© . All rights reserved.