对话框是非常重要的一种窗体,就我看过的应用,除了MDI程序,对话框比文档视图框架用得更多。原因大概有两个,首先对话框可以利用资源编辑器来编辑,这就有了一点快速开发的感觉,尽管比真正的快速开发弱得多;其次,对话框提供一种叫数据交换的方法,让控件与某种数据类型关联起来,比如Edit控件与CString变量关联,对CString变量的操作间接映射到Edit控件,这种方便性是不言而喻的。
对话框的创建
对话框如何创建,它是对SDK的对话框资源的封装,说得简单一点,就是对CreateDlgIndirect的封装。
对话框的显示几乎是MFC最简单的窗体创建,用下面两句代码就可以做到:
CMFCTest2Dlg dlg;
dlg.DoModal();
对话框资源对应一个资源ID,这个ID在对话框类构造时保存:
CMFCTest2Dlg::CMFCTest2Dlg(CWnd* pParent /*=NULL*/)
: CDialog(CMFCTest2Dlg::IDD, pParent)
{
... ...
}
DoModal只是利用这个ID创建对话框窗口,不过它还要做几件事情,让对话框融入MFC框架,总体上可以描述如下:
1. 根据资源ID从程序的资源段中读出对话框资源。
2. 将对话框的Owner窗口置为Disable。
3. 调用AfxHookWindowCreate监视对话框的创建,让对话框可以进行消息映射。
4. 调用CreateDlgIndirect创建对话框。
5. 调用RunModalLoop进入消息循环。
整个过程就是这样,创建之后与其他窗体类型没有什么区别,只是要操作对话框的控件会有些麻烦,好在MFC提供了数据交换。
数据交换
由于MFC的对话框直接封装自CreateDlgIndirect,因此对话框里面的控件并没有转换成相应的控件类,我们只能通过GetDlgItem取得控件句柄,然后使用API来操作这些控件,这又回到SDK时代了。
为了简化对话框控件的操作,MFC提出了数据交换。这里的数据交换分两种,一种是控件与数据类型的关联;另一种是控件与控件类的关联。
控件与数据类型怎么关联起来的呢?全靠CWnd::UpdateData(BOOL bSaveAndValidate)这个成员函数,如果bSaveAndValidate为True,数据从控件赋给类型变量;反之,数据从类型变量赋给控件。
假设一个CString变量m_Enter与IDC_ENTER的编辑控件关联,则我们只需这样写:
m_Enter = "Enter";
UpdateData(FALSE);
那么m_Enter的值就会赋给IDC_ENTER。看看UpdateData是怎么做到的:
BOOL CWnd::UpdateData(BOOL bSaveAndValidate)
{
CDataExchange dx(this, bSaveAndValidate);
DoDataExchange(&dx);
return bOK;
}
UpdateData创建一个CDataExchange实例,然后调用DoDataExchange进行数据交换。Dx保存着当前的对话框对象,DoDataExchange是一个虚成员函数,对话框要实现数据交换必须覆盖这个函数:
void CMFCTest2Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMFCTest2Dlg)
DDX_Text(pDX, IDC_ENTER, m_Enter);
//}}AFX_DATA_MAP
}
DDX_Text是类向导自动生成的,实现如下:
void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, CString& value)
{
//根据nIDC取得对话框控件
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
//从控件取得数据赋给Value
if (pDX->m_bSaveAndValidate)
{
int nLen = ::GetWindowTextLength(hWndCtrl);
::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen), nLen+1);
value.ReleaseBuffer();
}
//将值赋给控件
else
{
AfxSetWindowText(hWndCtrl, value);
}
}
DDX_Text仅仅是帮我们调用API,最后将值赋给类型变量, DDX_Text有很多重载形式,使得数据变量可以是Int,Short等其他类型。
数据交换的另一种形式是控件与控件类,比如有一个CButton类m_OK与IDOK关联,CDialog::OnInitDialog会调用UpdateData(FALSE),进而执行流程到DoDataExchange:
void CMFCTest2Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMFCTest2Dlg)
DDX_Control(pDX, IDOK, m_OK);
//}}AFX_DATA_MAP
}
看看DDX_Control做了什么:
void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl)
{
//只子类化一次
if (rControl.m_hWnd == NULL) // not subclassed yet
{
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
rControl.SubclassWindow(hWndCtrl);
}
}
DDX_Control将控件句柄与控件类关联起来,并且只需关联一次,实现关联的方法是子类化hWndCtrl :CWnd::SubclassWindow。这里的子类化其实做了两件事情,一件是通过Attach将控件句柄与控件类映射起来,另一件是通过SetWindowLong将窗口过程替换成AfxWndProc,使得控件也可以进行消息映射。
关联以后,m_OK就代表IDOK,以后直接操作m_OK即可。
控件关联给我们带来一种非常好的应用,我们在对话框资源上放一个Button的时候,只能处理Click和DbClick两个事件,如果我们想处理MouseMove消息要怎么做,只能继承CButton写一个派生类,然后在派生类里面处理MouseMove消息,但这样做就不能在资源编辑器上可视操作按钮了,我们必须手动创建按钮类,写代码控制它的位置,非常地麻烦。
其实使用数据交换就可以一举两得,让按钮派生类与对话框资源上的按钮关联起来,我们既能扩展按钮的消息处理,又能可视化设计按钮。
具体是这样做的:
1. 在对话框资源上放一个按钮IDOK。
2. 创建一个按钮类派生自CButton,并处理MouseMove消息:
BEGIN_MESSAGE_MAP(CMyButton, CButton)
//{{AFX_MSG_MAP(CMyButton)
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CMyButton::OnMouseMove(UINT nFlags, CPoint point)
{
MessageBox("Hello");
CButton::OnMouseMove(nFlags, point);
}
3. 利用类向导,将IDOK与一个按钮类关联起来:
class CMFCTest2Dlg : public CDialog
{
... ...
CButton m_OK;
CString m_Enter;
... ...
};
4. 将CButton设为CMyButton,完毕。
对话框的应用广泛就在于此,RAD其实还是起决定因素的。
相关推荐
点击运行弹出一个对话框,点击DIALOG1按钮弹出一个模态对话框,在该对话框的编辑框输入文本点击确定该对话框消失且输入的文本被显示到主对话框MainDialog中,点击DAILOG2按钮弹出一个非模态对话框,操作现象和模态...
7. **对话框数据交换(Dialog Data Exchange, DDX)** 和 **对话框数据验证(Dialog Data Validation, DDV)**:用于在对话框控件和成员变量之间自动交换和验证数据。 8. **对话框模板(Dialog Template)**:在...
DoDataExchange() 是 MFC 对话框类中的一个重要函数,它主要用于处理对话框数据交换和验证。在使用对话框资源时,DoDataExchange() 函数扮演着关键角色,它使得对话框中的控件与程序中的变量之间可以进行自动的数据...
3. 重写DoDataExchange()函数:用于数据交换,将控件值与成员变量关联。 4. 实现OnInitDialog()函数:在对话框初始化时执行的代码,可以用来设置初始状态或调整布局。 5. 显示对话框:使用`CDialog::Create()`或`...
对于性能敏感的应用,可能需要考虑减少不必要的重绘和调整,例如使用`UpdateData`控制数据交换,以及使用`CRectTracker`类进行实时预览。 总之,"商业编程-源码-对话框源代码 resizing_dlg_doc.zip"是一个关于使用...
"两对话框实现数据交换"是一个常见的功能需求,它允许用户在不同的对话框之间传递信息,提升用户体验并增强应用的功能性。在这个场景中,我们有两个对话框,通常称为Dialog1和Dialog2,它们之间需要进行数据传输。 ...
- MFC使用DDX(Dialog Data Exchange)机制在对话框控件和成员变量间进行数据交换。 - 在对话框类的DoDataExchange函数中,使用DDX_Text宏来定义数据交换规则,例如`DDX_Text(pDX, IDC_ADDEND_EDIT, m_editAddend)...
5. 对话框数据交换:利用MFC的DDX(Dialog Data Exchange)和DDV(Dialog Data Validation)机制,可以方便地在对话框控件和类成员变量之间交换数据,确保用户输入的合法性。 6. 实现命令:如果你的应用需要响应...
5. **通信机制**:父对话框和子对话框之间可能需要交换数据或通知状态改变。MFC提供了多种方式,如使用`SendMessage()`、设置成员变量,或者使用回调函数。 6. **事件处理**:子对话框关闭后,可能需要通知父对话框...
为了创建一个密码对话框,我们需要继承自`CDialog`类,并覆盖其`DoDataExchange`函数,以便处理控件间的数据交换。 在这个实例中,我们可能会有一个主对话框(Main Dialog)和一个密码对话框(Password Dialog)。...
首先,我们来看一下对话框数据交换(DDX,Dialog Data Exchange)。DDX机制是用来在对话框类的成员变量与对话框内的控件之间自动传递数据的。当用户在对话框中的控件(如编辑框Edit或复选框CheckBox)中输入数据时,...
2. **对话框类**:继承自`CDialog`,通常包含控件成员变量,用于访问对话框上的控件,并重写`DoDataExchange`函数进行数据交换。 3. **控件初始化**:在`OnInitDialog`函数中,将控件成员变量与对话框资源中的控件ID...
6. **数据交换(DataExchange)**:对话框中的控件值与对话框类成员变量之间的同步,通常通过DataExchange函数实现。 7. **对话框资源(Dialog Resources)**:在Visual Studio等开发环境中,可以通过资源编辑器...
- 需要注意的是,在对话框类中可以使用`DoDataExchange`方法来进行数据交换,这是MFC提供的数据绑定机制。 3. **添加控件**: - 打开对话框资源视图,添加一个静态文本控件,并设置其文字为“Hello World”。 - ...
4. **数据交换(Data Exchange)**:在MFC中,DoDataExchange()函数用于在对话框控件和类成员变量之间进行数据交换。当用户在对话框中输入数据后,MFC会自动调用这个函数,将控件值赋给相应的成员变量。 5. **单文档...
通过分析和学习这个"ccmduidialog.zip"中的源代码,开发者可以深入理解MFC对话框的工作原理,学习如何自定义对话框,处理用户输入,以及实现复杂的交互逻辑。这对于进行Windows桌面应用开发来说是非常有价值的实践。...
6. **对话框数据交换(Dialog Data Exchange, DDX)和对话框数据验证(Dialog Data Validation, DDV)**: MFC提供了DDX和DDV机制,用于在对话框控件和类成员变量之间自动交换和验证数据,简化了用户输入数据的处理。...
同时,可能还需要在OnDataExchange()中处理对话框数据的交换,确保用户输入的正确性。 ### 8. 测试与调试 编写完成后,通过编译运行程序,进行功能测试,确保所有运算都能正确执行。调试时,可以利用Visual Studio...
MFC对话框是MFC库中的关键组件,用于实现用户与应用程序之间的交互。对话框通常包含一组控件,如文本框、按钮、复选框等,用户通过这些控件输入信息或执行特定操作。 对话框在MFC中分为两种类型:模态对话框(Modal...
为了创建一个具有文件选择功能的对话框,我们需要继承自CDialog类并覆盖其DoDataExchange成员函数,以处理对话框控件的数据交换。 关键知识点: 1. **CFileDialog类**:MFC提供了CFileDialog类,它是用于打开或...