基础语法篇_6——对话框的创建与显示、动态创建按钮、控件的访问【控件调整|静态文本控件|编辑框控件】、对话框伸缩功能、输入焦点的传递、默认按钮的说明

本文详细讲解了MFC中对话框的创建、显示及控件操作技巧,包括模态与非模态对话框的区别,动态创建按钮,访问和调整控件,实现对话框伸缩功能,输入焦点传递,以及默认按钮的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

🔳🔳 绘制线条 、画刷绘图、绘制连续线条、绘制扇形效果的线条


🔳🔳 插入符【文本插入符|图形插入符】、窗口重绘、路径、字符输入【设置字体|字幕变色】


🔳🔳 菜单命令响应函数、菜单命令的路由、基本菜单操作、动态菜单操作、电话本实例


🔳🔳 对话框的创建与显示、动态创建按钮、控件的访问【控件调整|静态文本控件|编辑框控件】、对话框伸缩功能、输入焦点的传递、默认按钮的说明


🔳🔳 MFC对话框:逃跑按钮、属性表单、向导创建


🔳🔳 在对话框程序中让对话框捕获WM_KEYDOWN消息


🔳🔳 修改应用程序窗口的外观【窗口光标|图标|背景】、模拟动画图标、工具栏编程、状态栏编程、进度栏编程、在状态栏上显示鼠标当前位置、启动画面


🔳🔳 设置对话框、颜色对话框、字体对话框、示例对话框、改变对话框和控件的背景及文本颜色、位图显示

一、基本知识

对话框就是一个窗口,它不仅可以接收消息,而且可以被移动和关闭,甚至可以在客户区进行绘图。对话框相当于一个容器,在它上面能够放置各种各样的标准控件和扩展控件,使程序支持用户输入的手段更加丰富。

1.1 常用控件介绍

在MFC中,所以的控件类都由CWnd类派生的。因此控件也是窗口。通常控件作为对话框的子窗口而创建的。控件也可以出现在视类窗口、工具栏和状态条中。

MFC的控件类封装类控件的功能。

控件 功能 对应控件类
静态文本框(Static Text) 显示文本,一般不接受输入信息 CStatic
图像控件(Picture) 显示位图、图标、方框和图元文件,一般不接受输入信息 CStatic
编辑框(Edit Box) 输入并编辑正文,支持单行和多行编辑 CEdit
按钮(Button) 响应用户的输入,触发相应的事件 CButton
复选框(Check Box) 用于选择标记,可以有选中、未选中和不确定三种状态 CButton
单选按钮(Radio Button) 用于从两个或多个选项中选中一项 CButton
组框(Group Box) 显示正文和方框,主要用于将相关的一些控件(用于共同的目的)组织在一起 CButton
列表框(List Box) 显示一个列表,用户可以从该列表中选中一项或者多项 CListBox
组合框(Combo Box) 是一个编辑框和一个列表框的组合,分成简易式、下拉式和下拉列表式 CComboBox
滚动条(Scroll Bar) 主要用于从一个预定义范围值中迅速而有效地选取一个整数值 CScrollBar
1.2 对话框的种类

对话框分为两种:
🔲◼◾ 模态对话框
模态对话框是指当其显示时,程序会暂停执行,直到关闭这个模态对话框后,才能继续执行程序中其他任务。

模态对话框垄断了用户的输入,当一个模态对话框打开时,用户只能与该对话框进行交互。而其他用户界面对象接收不到输入信息。我们平时所遇到的大部分对话框都是模态对话框。

        例如:在Word中利用文件打开菜单命令显示一个 “打开” 对话框后,再用鼠标去选择其他菜单或者进行该对话框以外的任何操作时,只会听到嘟嘟声。这是因为 “打开” 对话框是一个模态对话框。

🔲◼◾ 非模态对话框
当非模态对话框显示时,允许转去执行程序中其他任务,而不用关闭这个对话框。

二、对话框的创建与显示

先创建一个virtual studio类型的单文档应用工程,程序名为Mybole。

点击帮助菜单的子菜单关于Mybole,会出现一个对话框。这是MFC为我们创建的一个“关于”对话框,主要用于显示程序的版本号和版权信息。

自己创建对话框,需要通过插入一个对话框资源。具体步骤:资源视图—>右键Dialog—>添加资源—>新建

这个新建的IDD_DIALOG1对话框中有两个按钮: OKCancel,并通过它们的属性对话框可以发现它们的ID分别为IDOKIDCANCEL。VC++已经为这两个按钮提供了默认的消息响应函数OnOKOnCancel它们实现的主要功能都是一样的,就是关闭对话框。因此当程序运行时,单击这两个按钮中的任何一个都可以关闭对话框。但是单击这两个按钮关闭对话框后,返回的结果值是不一样的。在程序中通常根据该返回值来判断用户单击的是哪个按钮,从而确定用户的行为:是确定还是取消当前操作。

我们选中IDD_DIALOG1这个对话框资源本身,打开其属性对话框,将其Caption属性设置为:“测试”,以下统称这个对话框为测试对话框。

在MFC中,对资源的操作通常都是通过一个与资源相关的类来完成的。对话框资源也有一个相应的基类: CDialog。CDialog类派生于CWnd类,所以它是一个与窗口相关的类,主要用来在屏幕上显示一个对话框。对话框本身也是一个窗口界面。

在MFC中对资源的操作是通过一个类来完成的,那么就需要创建一个类与这个新建的对话框资源相关联。
在新建的对话框上双击鼠标左键,可弹出添加MFC类的界面。
② 对话框 ID项的内容已经被自动填充,就是刚才新建的那个对话框资源标识:IDD_DIALOG1,并且在基类项中也指定了这个新类的基类: CDialogEx。可以更换成CDialog基类。
③ 设置新类名。在输入类名的同时, 头文件和源文件会自动填充。

生成的CTestDialog类的构造函数如下。此类与IDD_DIALOG1相关联。

CTestDialog::CTestDialog(CWnd* pParent /*=nullptr*/)
	: CDialog(IDD_DIALOG1, pParent)
{
   

}

在程序中显示此对话框。
1)先在帮助菜单后添加一个菜单项,打开其属性对话框,将其Caption属性设置为**“对话框”,PopUp设置为False**,并将其ID设置为IDM_DIALOG
在这里插入图片描述
2)为此子菜单添加COMMAND命令消息响应函数。视类CMyboleView捕获对话框菜单项命令响应。

2.1 模态对话框的创建

创建模态对话框需要调用CDialog类的成员函数:DoModal,该函数功能就是创建并显示一个模态对话框。其返回值将作为CDialog类的另一个成员函数:EndDialog的参数,功能是关闭模态对话框。

✨ 1)视类引入CTestDialog的头文件。
🔴1.1)视类源文件文件引入#include "CTestDialog.h
🟡 1.2)后续根据提示进行添加。

✨✨ 2)定义对话框对象,并利用此对象调用DoModal函数以产生一个模态对话框。

void CMyboleView::OnDialog()
{
   
	// TODO: 在此添加命令处理程序代码
	CTestDialog  dlg;
	dlg.DoModal();
}

运行程序,点击对话框菜单,即可弹出自己创建的测试对话框。在此点击菜单中的任意菜单项都不会反应。

📋📋 原因:因为当Mybole程序执行到CMyboleView类OnDialog函数中的DoModal这行代码时,它就会停在这行代码处,不再向下执行。只有这个模态对话框被关闭了之后,这行代码才会返回,程序才能继续执行。

2.2 非模态对话框的创建

创建非模态的对话框,需要利用CDialog类的Create成员函数。该函数具有以下两种形式的声明:

BOOL create(LPCTSTR lpszTemplateName,CWnd* pParentWnd = NULL);
BOOL create(UINT nIDTemplate, CWnd* pParentWnd = NULL);
  • 第一个参数:
         🔳 是对话框资源的ID(nIDTemplate参数)
         🔳 或者是对话框模板的名称(IpszTemplateName参数)。
  • 第二个参数指定了对话框的父窗口。
         如果其值是NULL,对话框的父窗口就是主应用程序窗口。

在CMyboleView类OnDialog函数中实现创建非模态对话框的功能。

void CMyboleView::OnDialog()
{
   
	// TODO: 在此添加命令处理程序代码
	//CTestDialog  dlg;
	//dlg.DoModal();

	CTestDialog dlg;
	dlg.Create(IDD_DIALOG1, this);
}

🔳◼◾ 问题一:运行Mybole程序,单击程序菜单栏上的对话框菜单,发现并未出现测试对话框窗口。
        📋📋 原因:当利用Create函数创建非模态对话框时,还需要调用ShowWindow函数将这个对话框显示出来。
        🟢🟢 解决:在Create函数调用后再调用显示函数ShowWindow函数

void CMyboleView::OnDialog()
{
   
	// TODO: 在此添加命令处理程序代码
	//CTestDialog  dlg;
	//dlg.DoModal();

	CTestDialog dlg;
	dlg.Create(IDD_DIALOG1, this);
	dlg.ShowWindow(SW_SHOW);
}

📢📢📢 DoModal函数创建对话框时不需要ShowWindow函输。这是因为DoModal函数本身就有显示模态对话框的作用。所以模态对话框不需要再调用ShowWindow函数来显示对话框了。


🔳◼◾ 问题二:运行程序,单击程序菜单栏上的对话框菜单,发现任然出现问题。

        📋📋 原因:创建的非模态对话框对象(dlg)是一个局部对象,当程序执行时会依次执行各条代码。当OnDialog函数的右大括号执行结束时,dlg这个对象的生命周期也就结束了,它就会销毁与之相关联的对话框资源。

📢📢📢 为什么上面创建模态对话框时就可以使用局部对象呢?
                上面已经讲过,在创建模态对话框时,当执行到调用DoModal函数以显示这个对话框时,程序就会暂停执行。直到模态对话框关闭之后,程序才继续向下执行。也就是说,当模态对话框显示时,程序中创建的dg这个对象的生命周期并未结束。

        🟢🟢 解决:在创建非模态对话框时,不能把对话框对象定义为局部对象。对于这个问题,有两种解决办法:
① 把这个对话框对象定义为视类的成员变量

  • 先定义dlg为一个视类成员变量:
  • 然后修改命令响应函数代码:
    void CMyboleView::OnDialog()
    {
         
    	// TODO: 在此添加命令处理程序代码
    	//CTestDialog  dlg;
    	//dlg.DoModal();
    
    	//CTestDialog dlg;
    	dlg.Create(IDD_DIALOG1, this);
    	dlg.ShowWindow(SW_SHOW);
    }
    
    ⭕ 问题2.1:运行程序,发现编译出错:

    🟢🟢 解决办法:在视类的头文件中引入CTestDialog的头文件。

② 将对话框对象定义为指针,在堆上分配内存。

📢📢📢 在堆上配的内存,与程序的整个生命周期是一致的(程序中不主动销毁)

void CMyboleView::OnDialog()
{
   
	// TODO: 在此添加命令处理程序代码
	//CTestDialog  dlg;
	//dlg.DoModal();

	CTestDialog*  dlg=new CTestDialog;
	dlg->Create(IDD_DIALOG1, this);
	dlg->ShowWindow(SW_SHOW);
}

⭕问题2.2:定义的dlg这个指针变量是一个局部对象,当它的生命周期结束时,它所保存的内存地址就丢失。那么在程序中也就无法再引用到它所指向的那块内存。
🟢🟢 解决:解决办法有两种:
① 将这个指针变量定义为视类(CMyboleView)的成员变量,然后在CMyboleView类的析构函数中调用delete函数来释放这个指针变量所指向的那块内存;

在构造函数中初始化,在析构函数中释放。

CMyboleView::CMyboleView() noexcept
{
   
	// TODO: 在此处添加构造代码
	pDlg = new CTestDialog;

}

CMyboleView::~CMyboleView()
{
   
	if (pDlg != NULL) {
   
		delete pDlg;
		pDlg = NULL;
	}
}

......

void CMyboleView::OnDialog()
{
   
	// TODO: 在此添加命令处理程序代码
	//CTestDialog  dlg;
	//dlg.DoModal();
	
	//CTestDialog* dlg = new CTestDialog;
	//dlg->Create(IDD_DIALOG1, this);
	//dlg->ShowWindow(SW_SHOW);
	
	pDlg->Create(IDD_DIALOG1, this);
	pDlg->ShowWindow(SW_SHOW);
}

② 在CTestDlg类中重载PostNcDestroy虚函数,释放this指针所指向的内存。

//CMyboleView.cpp
void CMyboleView::OnDialog()
{
   
	// TODO: 在此添加命令处理程序代码
	//CTestDialog  dlg;
	//dlg.DoModal();

	CTestDialog* dlg = new CTestDialog;
	dlg->Create(IDD_DIALOG1, this);
	dlg->ShowWindow(SW_SHOW);

	//pDlg->Create(IDD_DIALOG1, this);
	//pDlg->ShowWindow(SW_SHOW);
	
}

//CTestDialog.cpp
void CTestDialog::PostNcDestroy() {
   
	delete this;
	CDialog::PostNcDestroy();
}
//CTestDialog.h
protected:
    void PostNcDestroy();

2.3 OK按钮

        无论创建的是模态对话框,还是非模态对话框,当单击对话框上的OK按钮时,对话框都会消失。但有一点需要注意:

  • 模态对话框而言,此时对话框窗口对象被销毁了。
  • 非模态对话框来说,对话框窗口对象并未被销毁,只是隐藏起来了。

        非模态对话框中单击OK按钮后,程序所发生的事情:

1. 程序调用基类(CDialog)的OnOK函数,这是一个虚函数。
2. OnOK调用EndDialog函数,这个函数用于终止模态对话框,而对于非模态对话框,这个函数只是使对话框窗口不可见,并不销毁它。

        所以对于非模态对话框来说,如果有一个ID值为IDOK的按钮,就必须重写基类的OnOK这个虚函数,并在重写的函数中调用DestroyWindow函数,以完成销毁对话框的工作,同时注意不要再调用基类的OnOK函数。同样,如果非模态对话框中有一个ID值为IDCANCEL的按钮,也必须重写基类的OnCancel虚函数,并在重写的函数中调用DestroyWindow函数销毁对话框,同时注意不要再调用基类的OnCancel函数。

三、动态创建按钮

利用模态对话框实现一个功能:
        点击对话框中某个按钮,就在对话框中动态创建一个新按钮。

注释与非模态对话框有关的代码(一定要屏蔽掉CTestDlg类中重载的PostNcDestroy虚函数,否则程序运行会出现debug assertion failed错误)。恢复与模态框有关的代码。
✨ 1)为IDD_DIALOG1对话框添加一个按钮。

鼠标点击资源视图–>Dialog–>点击IDD_DIALOG1这个对话框资源ID,会打开对应的对话框资源。点击工具箱,会看到许多资源,将Button按钮拖动到对话框中

将添加的按钮的ID设置为IDC_BIN_ADD,Caption设置为:Add

✨✨ 2)响应Add按钮单击消息。为程序添加Add按钮点击消息的响应函数。

鼠标右键单击Add,选择类向导。因为现在是对CTestDialog对话框进

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值