`
isiqi
  • 浏览: 16487060 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

MFC控件篇之对话框

阅读更多
从VC提供的MFC类派生图中我们可以看出窗口的派生关系,所有的窗口类都是由CWnd派生。所有CWnd的成员函数在其派生类中都可以使用。本节介绍一些常用的功能给大家。

改变窗口状态:
BOOL EnableWindow( BOOL bEnable = TRUE );可以设置窗口的禁止/允许状态。BOOL IsWindowEnabled( );可以查询窗口的禁止/允许状态。
BOOL ModifyStyle( DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 )/BOOL ModifyStyleEx( DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 );可以修改窗口的风格,而不需要调用SetWindowLong
BOOL IsWindowVisible( ) 可以检查窗口是否被显示。
BOOL ShowWindow( int nCmdShow );将改变窗口的显示状态,nCmdShow可取如下值:

SW_HIDE 隐藏窗口
SW_MINIMIZE SW_SHOWMAXIMIZED 最小化窗口
SW_RESTORE 恢复窗口
SW_SHOW 显示窗口
SW_SHOWMINIMIZED 最大化窗口

改变窗口位置:
void MoveWindow( LPCRECT lpRect, BOOL bRepaint = TRUE );可以移动窗口。
void GetWindowRect( LPRECT lpRect ) ;可以得到窗口的矩形位置。
BOOL IsIconic( ) ;可以检测窗口是否已经缩为图标。
BOOL SetWindowPos( const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags );可以改变窗口的Z次序,此外还可以移动窗口位置。

使窗口失效,印发重绘:
void Invalidate( BOOL bErase = TRUE );使整个窗口失效,bErase将决定窗口是否产生重绘。
void InvalidateRect( LPCRECT lpRect, BOOL bErase = TRUE )/void InvalidateRgn( CRgn* pRgn, BOOL bErase = TRUE );将使指定的矩形/多边形区域失效。

窗口查找:
static CWnd* PASCAL FindWindow( LPCTSTR lpszClassName, LPCTSTR lpszWindowName );可以以窗口的类名和窗口名查找窗口。任一参数设置为NULL表对该参数代表的数据进行任意匹配。如FindWindow("MyWnd",NULL)表明查找类名为MyWnd的所有窗口。
BOOL IsChild( const CWnd* pWnd ) 检测窗口是否为子窗口。
CWnd* GetParent( ) 得到父窗口指针。
CWnd* GetDlgItem( int nID ) 通过子窗口ID得到窗口指针。
int GetDlgCtrlID( ) 得到窗口ID值。
static CWnd* PASCAL WindowFromPoint( POINT point );将从屏幕上某点坐标得到包含该点的窗口指针。
static CWnd* PASCAL FromHandle( HWND hWnd );通过HWND构造一个CWnd*指针,但该指针在空闲时会被删除,所以不能保存供以后使用。

时钟:
UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );可以创建一个时钟,如果lpfnTimer回调函数为NULL,窗口将会收到WM_TIMER消息,并可以在afx_msg void OnTimer( UINT nIDEvent );中安排处理代码
BOOL KillTimer( int nIDEvent );删除一个指定时钟。

可以利用重载来添加消息处理的虚函数:
afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct );窗口被创建时被调用
afx_msg void OnDestroy( );窗口被销毁时被调用
afx_msg void OnGetMinMaxInfo( MINMAXINFO FAR* lpMMI );需要得到窗口尺寸时被调用
afx_msg void OnSize( UINT nType, int cx, int cy );窗口改变大小后被调用
afx_msg void OnMove( int x, int y );窗口被移动后时被调用
afx_msg void OnPaint( );窗口需要重绘时时被调用,你可以填如绘图代码,对于视图类不需要重载OnPaint,所有绘图代码应该在OnDraw中进行
afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags );接收到字符输入时被调用
afx_msg void OnKeyDown/OnKeyUp( UINT nChar, UINT nRepCnt, UINT nFlags );键盘上键被按下/放开时被调用
afx_msg void OnLButtonDown/OnRButtonDown( UINT nFlags, CPoint point );鼠标左/右键按下时被调用
afx_msg void OnLButtonUp/OnRButtonUp( UINT nFlags, CPoint point );鼠标左/右键放开时被调用
afx_msg void OnLButtonDblClk/OnRButtonDblClk( UINT nFlags, CPoint point );鼠标左/右键双击时被调用
afx_msg void OnMouseMove( UINT nFlags, CPoint point );鼠标在窗口上移动时被调用
使用资源编辑器编辑对话框

在Windows开发中弹出对话框是一种常用的输入/输出手段,同时编辑好的对话框可以保存在资源文件中。Visual C++提供了对话框编辑工具,利用编辑工具可以方便的添加各种控件到对话框中,而且利用ClassWizard可以方便的生成新的对话框类和映射消息。

首先资源列表中按下右键,可以在弹出菜单中选择“插入对话框”,然后再打开该对话框进行编辑,你会在屏幕上看到一个控件板,你可以将所需要添加的控件拖到对话框上,或是先选中后再在对话框上用鼠标画出所占的区域。

接下来我们在对话框上产生一个输入框,和一个用于显示图标的图片框。之后我们使用鼠标右键单击产生的控件并选择其属性,我们可以在属性对话框中编辑控件的属性同时也需要指定控件ID,如果在选择对话框本身的属性那么你可以选择对话框的一些属性,包括字体,外观,是否有系统菜单等等。最后我们编辑图片控件的属性,我们设置控件的属性为显示图标并指明一个图标ID。

接下来我们添加一些其他的控件,最后的效果按下Ctrl-T可以测试该对话框。此外在对话框中还有一个有用的特性,就是可以利用Tab键让输入焦点在各个控件间移动,要达到这一点首先需要为控件设置在Tab键按下时可以接受焦点移动的属性Tab Stop,如果某一个控件不打算利用这一特性,你需要清除这一属性。然后从菜单“Layout”选择Tab Order来确定焦点移动顺序,使用鼠标依此点击控件就可以重新规定焦点移动次序。最后按下Ctrl-T进行测试。

最后我们需要为对话框产生新的类,ClassWizard可以替我们完成大部分的工作,我们只需要填写几个参数就可以了。在编辑好的对话框上双击,然后系统回询问是否添加新的对话框,选择是并在接下来的对话框中输入类名就可以了。ClassWizard会为你产生所需要的头文件和CPP文件。然后在需要使用的地方包含相应的头文件,对于有模式对话框使用DoModal()产生,对于无模式对话框使用Create()产生。相关代码如下;

void CMy51_s1View::OnCreateDlg()
{//产生无模式对话框
CTestDlg *dlg=new CTestDlg;
dlg->Create(IDD_TEST_DLG);
dlg->ShowWindow(SW_SHOW);
}

void CMy51_s1View::OnDoModal()
{//产生有模式对话框
CTestDlg dlg;
int iRet=dlg.DoModal();
TRACE("dlg return %d\n",iRet);
}

下载例子。如果你在调试这个程序时你会发现程序在退出后会有内存泄漏,这是因为我没有释放无模式对话框所使用的内存,这一问题会在以后的章节5.3 创建无模式对话框中专门讲述。

关于在使用对话框时Enter键和Escape键的处理:在使用对话框是你会发现当你按下Enter键或Escape键都会退出对话框,这是因为Enter键会引起CDialog::OnOK()的调用,而Escape键会引起CDialog::OnCancel()的调用。而这两个调用都会引起对话框的退出。在MFC中这两个成员函数都是虚拟函数,所以我们需要进行重载,如果我们不希望退出对话框那么我们可以在函数中什么都不做,如果需要进行检查则可以添加检查代码,然后调用父类的OnOK()或OnCancel()。相关代码如下;

void CTestDlg::OnOK()
{
AfxMessageBox("你选择确定");
CDialog::OnOK();
}

void CTestDlg::OnCancel()
{
AfxMessageBox("你选择取消");
CDialog::OnCancel();
}
创建有模式对话框

使用有模式对话框时在对话框弹出后调用函数不会立即返回,而是等到对话框销毁后才会返回(请注意在对话框弹出后其他窗口的消息依然会被传递)。所以在使用对话框时其他窗口都不能接收用户输入。创建有模式对话框的方法是调用CDialogDoModal()。下面的代码演示了这种用法:

CYourView::OnOpenDlg()
{
CYourDlg dlg;
int iRet=dlg.DoModal();
}

CDialogDoModal()的返回值为IDOK,IDCANCEL。表明操作者在对话框上选择“确认”或是“取消”。由于在对话框销毁前DoModal不会返回,所以可以使用局部变量来引用对象。在退出函数体后对象同时也会被销毁。而对于无模式对话框则不能这样使用,下节5.3 创建无模式对话框中会详细讲解。

你需要根据DoModal()的返回值来决定你下一步的动作,而得到返回值也是使用有模式对话框的一个很大原因。

使用有模式对话框需要注意一些问题,比如说不要在一些反复出现的事件处理过程中生成有模式对话框,比如说在定时器中产生有模式对话框,因为在上一个对话框还未退出时,定时器消息又会引起下一个对话框的弹出。

同样的在你的对话框类中为了向调用者返回不同的值可以调用CDialog::OnOK()或是CDialogOnCancel()以返回IDOK或IDCANCEL,如果你希望返回其他的值,你需要调用
CDialogEndDialog( int nResult );其中nResult会作为DoModal()调用的返回值。

下面的代码演示了如何使用自己的函数来退出对话框:

void CMy52_s1View::OnLButtonDown(UINT nFlags, CPoint point)
{//创建对话框并得到返回值
CView::OnLButtonDown(nFlags, point);
CTestDlg dlg;
int iRet=dlg.DoModal();
CString szOut;
szOut.Format("return value %d",iRet);
AfxMessageBox(szOut);
}
//重载OnOK,OnCancel
void CTestDlg::OnOK()
{//什么也不做
}
void CTestDlg::OnCancel()
{//什么也不做
}
//在对话框中对三个按钮消息进行映射
void CTestDlg::OnExit1()
{
CDialog::OnOK();
}
void CTestDlg::OnExit2()
{
CDialog::OnCancel();
}
void CTestDlg::OnExit3()
{
CDialog::EndDialog(0XFF);
}

由于重载了OnOK和OnCancel所以在对话框中按下Enter键或Escape键时都不会退出,只有按下三个按钮中的其中一个才会返回。

此外在对话框被生成是会自动调用BOOL CDialog::OnInitDialog(),你如果需要在对话框显示前对其中的控件进行初始化,你需要重载这个函数,并在其中填入相关的初始化代码。利用ClassWizard可以方便的产生一些默认代码,首先打开ClassWizard,选择相应的对话框类,在右边的消息列表中选择WM_INITDIALOG并双击,如图,ClassWizard会自动产生相关代码,代码如下:

BOOL CTestDlg::OnInitDialog()
{
/*先调用父类的同名函数*/
CDialog::OnInitDialog();
/*填写你的初始化代码*/
return TRUE;
}

有关对对话框中控件进行初始化会在5.4 在对话框中进行消息映射中进行更详细的讲解。
创建无模式对话框

无模式对话框与有模式对话框不同的是在创建后其他窗口都可以继续接收用户输入,因此无模式对话框有些类似一个弹出窗口。创建无模式对话框需要调用
BOOL CDialog::Create( UINT nIDTemplate, CWnd* pParentWnd = NULL );之后还需要调用
BOOL CDialog::ShowWindow( SW_SHOW);进行显示,否则无模式对话框将是不可见的。相关代码如下:

void CYourView::OnOpenDlg(void)
{
/*假设IDD_TEST_DLG为已经定义的对话框资源的ID号*/
CTestDlg *dlg=new CTestDlg;
dlg->Create(IDD_TEST_DLG,NULL);
dlg->ShowWindows(SW_SHOW);
/*不要调用 delete dlg;*/
}

在上面的代码中我们新生成了一个对话框对象,而且在退出函数时并没有销毁该对象。因为如果此时销毁该对象(对象被销毁时窗口同时被销毁),而此时对话框还在显示就会出现错误。那么这就提出了一个问题:什么时候销毁该对象。我时常使用的方法有两个:
在对话框退出时销毁自己:在对话框中重载OnOK与OnCancel在函数中调用父类的同名函数,然后调用DestroyWindow()强制销毁窗口,在对话框中映射WM_DESTROY消息,在消息处理函数中调用delete this;强行删除自身对象。相关代码如下:
void CTestDlg1::OnOK()
{
CDialog::OnOK();
DestroyWindow();
}

void CTestDlg1::OnCancel()
{
CDialog::OnCancel();
DestroyWindow();
}

void CTestDlg1::OnDestroy()
{
CDialog::OnDestroy();
AfxMessageBox("call delete this");
delete this;
}

这种方法的要点是在窗口被销毁的时候,删除自身对象。所以你可以在任何时候调用DestroyWindow()以达到彻底销毁自身对象的作用。(DestroyWindow()的调用会引起OnDestroy()的调用)
通过向父亲窗口发送消息,要求其他窗口对其进行销毁:首先需要定义一个消息用于进行通知,然后在对话框中映射WM_DESTROY消息,在消息处理函数中调用消息发送函数通知其他窗口。在接收消息的窗口中利用ON_MESSAGE映射处理消息的函数,并在消息处理函数中删除对话框对象。相关代码如下:
/*更改对话框的有关文件*/
CTestDlg2::CTestDlg2(CWnd* pParent /*=NULL*/)
: CDialog(CTestDlg2::IDD, pParent)
{/*m_pParent为一成员变量,用于保存通知窗口的指针,
所以该指针不能是一个临时指针*/
ASSERT(pParent);
m_pParent=pParent;
//{{AFX_DATA_INIT(CTestDlg2)
// NOTE: the ClassWizard will add member
initialization here
//}}AFX_DATA_INIT
}
void CTestDlg2::OnOK()
{
CDialog::OnOK();
DestroyWindow();
}

void CTestDlg2::OnCancel()
{
CDialog::OnCancel();
DestroyWindow();
}

void CTestDlg2::OnDestroy()
{
CDialog::OnDestroy();
/*向其他窗口发送消息,将自身指针作为一个参数发送*/
m_pParent->PostMessage(WM_DELETE_DLG,
(WPARAM)this);
}

/*在消息接收窗口中添加消息映射*/
/*在头文件中添加函数定义*/
afx_msg LONG OnDelDlgMsg(WPARAM wP,
LPARAM lP);
/*添加消息映射代码*/
ON_MESSAGE(WM_DELETE_DLG,OnDelDlgMsg)
END_MESSAGE_MAP()
/*实现消息处理函数*/
LONG CMy53_s1View::OnDelDlgMsg(WPARAM wP,LPARAM lP)
{
delete (CTestDlg2*)wP;
return 0;
}
/*创建对话框*/
void CMy53_s1View::OnTest2()
{
CTestDlg2 *dlg=new CTestDlg2(this);
dlg->Create(IDD_TEST_DLG_2);
dlg->ShowWindow(SW_SHOW);
}

在这种方法中我们利用消息来进行通知,在Window系统中利用消息进行通知和传递数据的用法是很多的。

同样无模式对话框的另一个作用还可以用来在用户在对话框中的输入改变时可以及时的反映到其他窗口。下面的代码演示了在对话框中输入一段文字,然后将其更新到视图的显示区域中,这同样也是利用了消息进行通知和数据传递。

/*在对话框中取出数据,并向其他窗口发送消息和数据,
将数据指针作为一个参数发送*/
void CTestDlg2::OnCommBtn()
{
char szOut[30];
GetDlgItemText(IDC_OUT,szOut,30);
m_pParent->SendMessage(WM_DLG_NOTIFY,
(WPARAM)szOut);
}

/*在消息接收窗口中*/
/*映射消息处理函数*/
ON_MESSAGE(WM_DLG_NOTIFY,OnDlgNotifyMsg)

/*在视图中绘制出字符串 m_szOut*/
void CMy53_s1View::OnDraw(CDC* pDC)
{
CMy53_s1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->TextOut(0,0,"Display String");
pDC->TextOut(0,20,m_szOut);
}
/*处理通知消息,保存信息并更新显示*/
LONG CMy53_s1View::OnDlgNotifyMsg(WPARAM wP,LPARAM lP)
{
m_szOut=(char*)wP;
Invalidate();
return 0;
}


此外这种用法利用消息传递数据的方法对有模式对话框和其他的窗口间通信也一样有效。






分享到:
评论

相关推荐

    MFC 对话框中控件随对话框大小改变而改变

    在MFC(Microsoft Foundation Classes)框架中,对话框(Dialog)是用户界面的重要组成部分,它包含了一系列的控件,如按钮、文本框等。当对话框的大小发生变化时,有时我们希望对话框内的控件能相应地调整大小,以...

    MFC中子对话框的大小随tab控件的大小改变而改变

    MFC中,包含多个对话框,子对话框在Tab控件中显示,让子对话框中的控件跟随主对话框大小变化而变化,字体也能够缩放,但是不能加载图片控件,只对控件和字体缩放,单个对话框也适用,简单易懂。主要有一个CLout类,...

    MFC控件与对话框

    MFC控件与对话框,专门对基于对话框的基本控件实用讲解

    使控件与对话框同步大小变化

    6. **使用锚点和约束**:现代的MFC或WPF应用程序可能使用更高级的布局系统,如Windows Presentation Foundation (WPF)的Grid或Canvas,它们支持使用锚点和约束来定义控件相对于对话框或其他控件的位置和大小。...

    MFC做的基于对话框的密码登录

    对话框是由各种控件组成的,这些控件接收用户输入并显示信息。在密码登录程序中,常见的控件包括: 1. **EDIT控件**:用于用户输入文本,如用户名和密码输入框。 2. **STATIC控件**:通常作为标签,显示提示信息,...

    MFC实现多个对话框

    本篇将详细介绍如何使用MFC来实现多个对话框,并通过实际的代码示例进行解析。 首先,我们需要理解MFC中的对话框类,主要是CDialog派生类。对话框通常由资源编辑器创建,包含各种控件如按钮、文本框、复选框等。在...

    MFC添加对话框滚动条功能

    1. 在MFC应用程序中,打开“资源视图”,找到对话框资源,右键选择“插入控件”。 2. 在控件列表中找到“滚动条”(SCROLLBAR),并将其拖放到对话框上。确保为滚动条设置正确的ID(例如IDC_SCROLLBAR1)。 3. 在...

    MFC设置位图为对话框背景

    本篇文章将深入探讨如何在MFC对话框中设置位图作为背景,以及这一操作可能涉及的相关技术。 首先,我们需要了解对话框的基本概念。对话框是Windows应用程序中一种用于与用户交互的窗口,通常包含各种控件,如按钮、...

    MFC实现嵌入式对话框,显示子对话框到主对话框中的对应位置

    在MFC中,我们可以通过继承`CDialog`类来创建自定义对话框,并将其作为控件添加到主对话框上。 1. 创建子对话框类: - 创建一个新的派生自`CDialog`的类,例如`CInnerDialog`。 - 在类中定义对话框资源,并在IDD_...

    用VC++MFC做的基于对话框的时钟程序

    2. **CDialog类**:用于创建对话框,它是MFC中的核心类之一。在这个项目中,对话框作为主界面,承载指针时钟和电子时钟的显示。 3. **CStatic控件**:MFC中的CStatic类用于创建静态文本或图像,可以用来显示时钟的...

    MFC模态 非模态对话框 ARX2008+VS2005

    在MFC中,对话框数据的获取和设置通常通过`DoDataExchange()`函数完成,该函数负责在对话框控件与成员变量之间交换数据。数据验证可以在`OnInitDialog()`中或自定义的验证函数中进行,以确保用户输入的有效性。 6. ...

    MFC中全屏显示对话框

    本篇将详细探讨如何实现MFC中的全屏对话框,并通过提供的源代码进行深入理解。 首先,我们来了解MFC对话框的基本概念。MFC中的对话框(CDialog类)是基于Windows API的对话框窗口的抽象,用于与用户交互。对话框...

    MFC.rar_MFC 对话框_MFC 对话框 交互_对话框

    在文档“MFC函数----对话框.doc”中,可能包含了关于如何创建、使用和管理MFC对话框的更详细信息,包括控件的使用、事件处理、对话框的动态创建等。深入学习这些内容,有助于开发者更好地构建具有丰富交互功能的...

    MFC控件随对话框尺度变化

    本文将深入探讨如何在MFC环境中实现对话框及其控件随对话框尺度变化的功能,具体通过一个使用VS2017开发的示例项目"ControlDemo"来说明。 首先,我们要了解MFC中的对话框(CDialog)类,它是Windows对话框的抽象,...

    MFC对话框自适应助手

    MFC做界面时,经常会遇到对话框大小改变时,控件和子对话框也需要同比例的改变,查了好多资料,没找到好的,自己写了个类,测试效果还不错,最关键的是用起来非常方便,只需要在最顶层主对话框初始化时调用Init()...

    MFC中子对话框的大小跟随主对话框大小进行缩放

    常用的MFC控件(包括字体、BMP控件)都可以进行缩放,子对话框的控件也可跟随主对话框大小缩放。单个对话框也适用。界面的控件ID循环查找存入数组中(这样界面可随意添删控件也不需要改变代码,注意控件ID不允许重复...

    在ObjectARX中使用MFC-标签式对话框 项目源代码

    5. 对话框数据交换:利用MFC的DDX(Dialog Data Exchange)和DDV(Dialog Data Validation)机制,可以方便地在对话框控件和类成员变量之间交换数据,确保用户输入的合法性。 6. 实现命令:如果你的应用需要响应...

    MFC 一般属性页对话框

    **MFC 一般属性页对话框** MFC(Microsoft Foundation Classes)是一套C++类库,用于构建Windows应用程序,特别是图形用户界面(GUI)应用。在Visual Studio 2017中,MFC提供了一种方便的方式来实现属性页对话框,...

    在VS2013上的MFC树控件操作(连接对话框)

    对话框(Dialog)是MFC应用程序中用于与用户交互的窗口,通常包含各种控件,如按钮、文本框和树控件等。本教程将重点讲解如何在对话框中操作MFC树控件,并解决子节点字符串重复时添加不同对话框的问题。 1. **MFC树...

Global site tag (gtag.js) - Google Analytics