mfc对话框基础要点

mfc对话框基础要点
mfc对话框基础要点

第五章对话框

对话框是一种用户界面,它的主要功能是输出信息和接收用户的输入。对话框与控件是密不可分的,在每个对话框内一般都有一些控件,对话框依靠这些控件与用户进行交互。一个典型的对话框例子是选择了File-Open命令后弹出的文件对话框。

5.1对话框和控件的基本概念

5.1.1对话框的基本概念

对话框(Dialog)实际上是一个窗口。在MFC中,对话框的功能被封装在了CDialog类中,CDialog类是CWnd类的派生类。

对话框分为模态对话框和非模态对话框两种。大部分读者都会有这样的经历,当你通过File-Open命令打开一个文件对话框后,再用鼠标去选择菜单将只会发出嘟嘟声,这是因为文件对话框是一个模态对话框。模态对话框垄断了用户的输入,当一个模态对话框打开时,用户只能与该对话框进行交互,而其它用户界面对象收不到输入信息。我们平时所遇到的大部分对话框都是模态对话框。非模态对话框的典型例子是Windows95提供的写字板程序中的搜索对话框,搜索对话框不垄断用户的输入,打开搜索对话框后,仍可与其它用户界面对象进行交互,用户可以一边搜索,一边修改文章,这样就大大方便了使用。

本节主要介绍模态对话框,在第四节将介绍非模态对话框。

从MFC编程的角度来看,一个对话框由两部分组成:

1.对话框模板资源。对话框模板用于指定对话框的控件及其分布,Windows根据对话框模板来创建并显示对话框。

2.对话框类。对话框类用来实现对话框的功能,由于对话框行使的功能各不相同,因此一般需要从CDialog类派生一个新类,以完成特定的功能。

5.1.2控件的基本概念

图5.1对话框中的控件

控件(Control)是独立的小部件,在对话框与用户的交互过程中,控件担任着主要角色。控件的种类较多,图5.1显示了对话框中的一些基本的控件。MFC的控件类封装了控件的功能,表5.1介绍了一些常用的控件及其对应的控件类。

表5.1

子窗口而创建的,控件也可以出现在视窗口,工具条和状态条中。

对话框的设计包括对话框模板的设计和对话框类的设计两个主要方面。

1.与对话框有关的消息主要包括WM_INITDIALOG消息和控件通知消息。在对话框创建时,会收到WM_INITDIALOG消息,对话框对该消息的处理函数是OnInitDialog 。

2.OnInitDialog的主要用处是初始化对话框。对话框的控件会向对话框发送控件通知消息,以表明控件的状态发生了变化。

5.2对话框模板的设计

利用Developer Studio提供的可视化设计工具,用户可以方便地设计对话框模板。

请读者按前面章节介绍的方法利用AppWizard建立一个名为Register的MFC应用程序,并在进入MFC AppWizard对话框后按下面几步操作:

1.在第1步中选中Single document以建立一个单文档应用程序。

2.在第4步中使Docking toolbar项不选中,这样AppWizard就不会创建工具条。

3.在第6步中先选择CRegisterView,然后在Base class栏中选择CEditView,这样

CRegisterView将是CEditView的继承类,从而使视图具有了编辑功能。

编译并运行Register,读者会发现Register居然是个编辑器,它可以打开、编辑和保存文本文件。当然,Register的目的不仅仅是个编辑器。假设要对某一地区的就业情况进行调查,我们希望Register程序能够登录就业情况数据并将数据存储起来。

要登录数据,用对话框是再合适不过了。一个典型的就业情况登录对话框如图5.1所示,本节的任务就是设计如图5.1的中文对话框模板。

切换至资源视图,选择Insert-Resource命令,并在Insert Resource对话框中双击Dialog项。完成后在资源视图中会出现一个名为IDD_DIALOG1的新的对话框模板资源。双击IDD_DIALOG1,则会打开该对话框模板的编辑窗口,如图5.2所示。缺省的对话框模板有OK和Cancel两个按钮,在窗口的旁边有一个控件面板,在控件面板上用鼠标选择一个控件,然后在对话框中点击,则相应的控件就被放置到了对话框模板中。图5.3显示了控件面板上的按钮所代表的控件。读者不用记忆图5.3的内容,如果不能确定控件的类型,可将鼠标在某个控件按钮上停留片刻,则会显示一个工具提示,指出该按钮所代表控件的名称。

图5.2 缺省的对话框模板

图5.3 控件面板

读者可以在对话框模板中随意加几个控件试试看。当用鼠标选择对话框或控件时,会出现一个围绕它的虚框,拖动虚框的边界可以改变对话框或控件的大小,在Developer Studio 的状态条中会显示出所选对象的坐标和尺寸。控件可以被拖动,也可以按箭头键来移动选中的控件。在拖动控件时若按住Ctrl键,则控件会被复制。

用户可以一次选择多个控件,选择的方法有两个:1。在对话框的空白处拖动鼠标,则拖动出来的虚线框内的控件将被选中。2。在选择控件时按住Ctrl键,则可以多重选择。选中控件或对话框后按回车键,则会弹出一个属性对话框,属性对话框用来设置控件或对话框的各种属性。属性对话框是标签式对话框,第一页是常规属性(General)。一个典型的控件属性对话框如图5.4所示。如果对属性对话框中的选项的意思不明白,可以按F1键获得帮助。

图5.4 控件属性对话框

在控件属性对话框的常规属性中,有一些控件共同的属性:

?ID属性。用于指定控件的标识符,Windows依靠ID来区分不同的控件。

?Caption(标题)属性。静态正文、组框、按钮、检查框、单选按钮等控件可以显示标题,用来对控件进行文字说明。控件标题中的字符使紧跟其后的字符有下划线,按Alt+下划线将启动该控件。若控件是一个单选按钮,则Alt+下划线字符将选择该按钮;若是检查框,则相当于对该检查框按空格键;若是按钮,则将激活按钮命令;若控件是一个静态正文,则将激活按tab顺序紧随其后的下一个控件。

?Visible属性。用来指定控件是否是可见的。

?Disable属性。使控件允许或禁止,一个禁止的控件呈灰色显示,不能接收任何输入。?Tabstop属性。用户可以按Tab键移动到具有Tabstop属性的控件上。Tab移动的顺序可以由用户指定。按Ctrl+D则Tab顺序会显示出来,如图5.5,用户可以用鼠标来重新指定Tab顺序。缺省的Tab顺序是控件的创建次序。

?Group属性。用来指定一组控件,用户可以用箭头键在该组控件内移动。在同一组内的单选按钮具有互斥的特性,即在这些单选按钮中只能有一个是选中的。如果一个控件具有Group属性,则这个控件以及按Tab顺序紧随其后的所有控件都属于一组的,直到遇到另一个有Group属性的控件为止。

现在就开始进行对话框模板的设计。首先,用鼠标选中对话框,按回车键,在弹出的属性对话框中将ID改为IDD_REGISTER并指定对话框的标题为“登录数据”。需要注意的是,由于要在对话框中显示汉字,因此必须设定正确的语种和字体。请读者在工作区资源视图的Dialog类型中单击鼠标选中IDD_REGISTER项,然后按Alt+Enter键,并在弹出的属性对话框中的Language栏中选择Chinese(P.R.C.)。接着,打开模板的属性对话框,单击Font...按钮,并选择“宋体”。

接着,请将对话框模板上的所有控件删除,删除的办法是选择控件后按Del键。为了容纳所有需要的控件,需将对话框的尺寸扩大到280×180。然后,请读者按图5.1和表5.2

表5.2

(风格)页的Type栏中选择的,这使得IDC_KIND成为一个下拉列表式组合框。组合框有简易式(Simple)、下拉式(Dropdown)和下拉列表式(Drop List)三种。简易式组合框包含一个编辑框和一个总是显示的列表框。下拉式组合框同简易式组合框的区别在于仅当单击下滚箭头时才出现列表框。下拉列表式组合框也有一个下拉的列表框,但它的编辑框是只读的,不能输入字符。组合框IDC_KIND不要自动排序,因此需在Styles页中使Sort项不被选中。

组合框的列表项可以在设计模板时初始化,而列表框的初始化只能在程序中进行。请读者在组合框IDC_KIND的属性对话框的General页中输入以下几个列表项,以作为单位性质的选项。输入时要注意,换行时不要按回车键,而应按Ctrl+回车键。

国有企事业

集体企业

私有企业

中外合资

外商独资

组合框控件的一个与众不同之处是它有两个尺寸,一个是下拉前的尺寸,一个是下拉后的尺寸。当用鼠标点击组合框上的箭头后,可设定下拉后的尺寸。

控件最好都放在对话框模板的蓝色虚框内,控件之间的距离不要太近,否则有可能造成不正确的显示。

安置好控件之后,下一步的任务是指定Tab顺序。按Ctrl+D键后,会显示当前的Tab 顺序,通过用鼠标点击控件可以设定新的Tab顺序,如果想放弃本次修改,在对话框的空白处点击一下即可。请读者按图5.5安排Tab顺序。

图5.5 对话框的Tab顺序

最后,需要测试一下对话框。按Ctrl+T,则会弹出一个当前模板的测试对话框,这个对话框的外观和基本行为与程序中将要弹出的对话框一样。这样,读者不用编译运行程序,通过测试对话框就可以评估对话框是否合乎要求。如果发现了错误或不满意的地方,可按ESC键退出测试对话框并重新修改对话框模板。

至此,对话框模板的设计就完成了。

5.3 对话框类的设计

完成对话框模板的设计后,就需要设计一个对话框类以实现对话框的功能。设计对话框类主要包括下面几步:

创建对话框类。该类应从CDialog类派生。

为对话框类加入与控件相对应的成员变量。

为对话框进行初始化工作。

增加对控件通知消息的处理

5.3.1对话框类的创建

利用ClassWizard,程序员可以十分方便的创建MFC窗口类的派生类,对话框类也不例外。请读者按以下几步操作:

打开IDD_REGISTER对话框模板,然后按Ctrl+W进入ClassWizard。

进入ClassWizard后,ClassWizard发现IDD_REGISTER是一个新的对话框模板,于是它会询问是否要为IDD_REGISTER创建一个对话框类。按OK键确认。

如图5.6在Create New Class对话框中,在Name栏中输入CRegisterDialog,在Base class栏中选择CDialog,在Dialog ID栏中选择IDD_REGISTER。按Create按钮后,对话框类CRegisterDialog即被创建。

图5.6 Create New Class对话框

ClassWizard自动使类CRegesterDialog与IDD_REGISTER模板联系起来。

5.3.2为对话框类加入成员变量

对话框的主要功能是输出和输入数据,例子中的登录数据对话框的任务就是输入数据。对话框需要有一组成员变量来存储数据。在对话框中,控件用来表示或输入数据,因此,存储数据的成员变量应该与控件相对应。

与控件对应的成员变量即可以是一个数据,也可以是一个控件对象,这将由具体需要来确定。例如,可以为一个编辑框控件指定一个数据变量,这样就可以很方便地取得或设置编辑框控件所代表的数据,如果想对编辑框控件进行控制,则应该为编辑框指定一个CEdit

对象,通过CEdit对象,程序员可以控制控件的行为。需要指出的是,不同类的控件对应的数据变量的类型往往是不一样的,而且一个控件对应的数据变量的类型也可能有多种。表5.3说明了控件的数据变量的类型。

表5.3

步骤操作。

按Ctrl+W进入ClassWizard。

选择ClassWizard上部的Member Variables标签,然后在Class name栏中选择

CRegisterDialog。这时,在下面的变量列表中会出现对话框控件的ID,如图5.7所示。

图5.7 ClassWizard对话框

双击列表中的ID_AGE会弹出Add Member Variable对话框,如图5.8所示。在Member variable name栏中输入m_nAge,在Category栏中选择Value,在Variable type栏中选择UINT。按OK按钮后,数据变量m_nAge就会被加入到变量列表中。

仿照第3步和表5.4,为各个控件加入相应的成员变量。

将m_nAge的值限制在16到65之间。方法是先选择m_nAge,然后在ClassWizard对话框的左下角输入最大和最小值。m_nAge代表年龄,这里规定被调查的人的年龄应在16岁以上,64岁以下。有了这个限制后,对话框会对输入的年龄值进行有效性检查,若输入的值不在限制范围内,则对话框会提示用户输入有效的值。

读者会注意到控件IDC_INCOME居然有两个变量,一个是CString型的,一个是CListBox 型的,这是完全合法的,不会引起任何冲突。之所以要加入CListBox型的变量,是因为列表框的初始化要通过CListBox对象进行。

提示:在ClassWizard中可分别为一个控件指定一个数据变量和一个控件对象,这样做的好处是即能方便地获得数据,又能方便地控制控件。

图5.8 Add Member Variable对话框

表5.4

5.3.3对话框的初始化

对话框的初始化工作一般在构造函数和OnInitDialog函数中完成。在构造函数中的初始化主要是针对对话框的数据成员。读者可以找到CRegisterDialog的构造函数,如清单5.1所示。

清单5.1 CRegisterDialog的构造函数

CRegisterDialog::CRegisterDialog(CWnd* pParent /*=NULL*/)

: CDialog(CRegisterDialog::IDD, pParent)

{

//{{AFX_DATA_INIT(CRegisterDialog)

m_nAge = 0;

m_strIncome = _T("");

m_strKind = _T("");

m_bMarried = FALSE;

m_strName = _T("");

m_nSex = -1;

m_strUnit = _T("");

m_nWork = -1;

//}}AFX_DATA_INIT

}

可以看出,对数据成员的初始化是由ClassWizard自动完成的。若读者对初值的含义还不太清楚,请参看表5.3。

在对话框创建时,会收到WM_INITDIALOG消息,对话框对该消息的处理函数是OnInitDialog。调用OnInitDialog时,对话框已初步创建,对话框的窗口句柄也已有效,但对话框还未被显示出来。因此,可以在OnInitDialog中做一些影响对话框外观的初始化

OnInitDialog是WM_INITDIALOG消息的处理函数,所以要用ClassWizard为RegisteritDialog类增加一个WM_INITDIALOG消息的处理函数,增加的方法是进入ClassWizard后,先选中MessageMaps标签,然后在Class name中选择CRegisterDialog,在Object IDs栏中选择CRegisterDialog,在Messages栏中找到WM_INITDIALOG并双击之,最后按OK按钮退出ClassWizard。

请读者按清单5.2修改OnInitDialog函数。

清单5.2 OnInitDialog函数

BOOL CRegisterDialog::OnInitDialog()

{

CDialog::OnInitDialog();

// TODO: Add extra initialization here

m_ctrlIncome.AddString("500元以下");

m_ctrlIncome.AddString("500-1000元");

m_ctrlIncome.AddString("1000-2000元");

m_ctrlIncome.AddString("2000元以上");

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

// EXCEPTION: OCX Property Pages should return FALSE

}

CRegisterDialog::OnInitDialog()的主要任务是对工资收入列表框的列表项进行初始化。调用CListBox::AddString可将指定的字符串加入到列表框中。由于该列表是不自动排序的,因此AddString将表项加在列表框的末尾。

5.3.4对话框的数据交换机制

对话框的数据成员变量存储了与控件相对应的数据。数据变量需要和控件交换数据,以完成输入或输出功能。例如,一个编辑框即可以用来输入,也可以用来输出:用作输入时,用户在其中输入了字符后,对应的数据成员应该更新;用作输出时,应及时刷新编辑框的内容以反映相应数据成员的变化。对话框需要一种机制来实现这种数据交换功能,这对对话框来说是至关重要的。

MFC提供了类CDataExchange来实现对话框类与控件之间的数据交换(DDX),该类还提供了数据有效机制(DDV)。数据交换和数据有效机制适用于编辑框、检查框、单选按钮、列表框和组合框。

数据交换的工作由CDialog::DoDataExchange来完成。读者可以找到CRegisterDialog::DoDataExchange函数,如清单5.3所示。

清单5.3 DoDataExchange函数

void CRegisterDialog::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CRegisterDialog)

DDX_Control(pDX, IDC_INCOME, m_ctrlIncome);

DDX_LBString(pDX, IDC_INCOME, m_strIncome);

DDX_CBString(pDX, IDC_KIND, m_strKind);

DDX_Check(pDX, IDC_MARRIED, m_bMarried);

DDX_Text(pDX, IDC_NAME, m_strName);

DDX_Radio(pDX, IDC_SEX, m_nSex);

DDX_Text(pDX, IDC_UNIT, m_strUnit);

DDX_Radio(pDX, IDC_WORK, m_nWork);

DDX_Text(pDX, IDC_AGE, m_nAge);

DDV_MinMaxUInt(pDX, m_nAge, 16, 65);

//}}AFX_DATA_MAP

}

读者可以看出,该函数中的代码是由ClassWizard自动加入的。DoDataExchange只有一个参数,即一个CDataExchange对象的指针pDX。在该函数中调用了DDX函数来完成数据交换,调用DDV函数来进行数据有效检查。

当程序需要交换数据时,不要直接调用DoDataExchange函数,而应该调用

CWnd::UpdateData。UpdataData函数内部调用了DoDataExchange。该函数只有一个布尔型参数,它决定了数据传送的方向。调用UpdateData(TRUE)将数据从对话框的控件中传送到对应的数据成员中,调用UpdateData(FALSE)则将数据从数据成员中传送给对应的控件。

在缺省的CDialog::OnInitDialog中调用了UpdateData(FALSE),这样,在对话框创建时,数据成员的初值就会反映到相应的控件上。若用户是按了OK(确定)按钮退出对话框,则对话框认为输入有效,就会调用UpdataData(TRUE)将控件中的数据传给数据成员。图5.9描绘了对话框的这种数据交换机制。

图5.9 对话框的数据交换

5.3.5对话框的运行机制

在程序中运行模态对话框有两个步骤:

在堆栈上以变量的形式构建一个对话框对象。

调用CDialog::DoModal ( )。

DoModal负责对模态话框的创建和撤销。在创建对话框时,DoModal的任务包括载入对话框模板资源、调用OnInitDialog初始化对话框和将对话框显示在屏幕上。完成对话框的创建后,DoModal启动一个消息循环,以响应用户的输入。由于该消息循环截获了几乎所有的输入消息,使主消息循环收不到对对话框的输入,致使用户只能与模态对话框进行交互,而其它用户界面对象收不到输入信息。

若用户在对话框内点击了ID为IDOK的按钮(通常该按钮的标题是“确定”或“OK”),或按了回车键,则CDialog::OnOK将被调用。OnOK首先调用UpdateData(TRUE)将数据从控件传给对话框成员变量,然后调用CDialog::EndDialog关闭对话框。关闭对话框后,DoModal 会返回值IDOK。

若用户点击了ID为IDCANCEL的按钮(通常其标题为“取消”或“Cancel”),或按了ESC键,则会导致CDialog::OnCancel的调用。该函数只调用CDialog::EndDialog关闭对话框。关闭对话框后,DoModal会返回值IDCANCEL。

程序根据DoModal的返回值是IDOK还是IDCANCEL就可以判断出用户是确定还是取消了对对话框的操作。

在弄清了对话框的运行机制后,下面让我们来就可以实现Register程序登录数据的功能。

首先,将Register工程的工作区切换至资源视图。打开IDR_MAINFRAME菜单资源,在Edit菜单的底端加入一个名为“登录数据”的新菜单项,并令其ID为ID_EDIT_REGISTER (最好在该项之前加一条分隔线,以便和前面的菜单项分开)。注意不要忘了把菜单资源的语种设置成中文,否则菜单中将显示不出中文来。设置的方法是先在工作区资源视图中选择IDR_MAINFRAME菜单资源,然后按Alt+Enter键,并在弹出的属性对话框中的Language栏中选择Chinese(P.R.C.)。

接着,用ClassWizard为该菜单命令创建命令处理函数

CRegisterView::OnEditRegister。注意,OnEditRegister是类CRegisterView的成员函数,这是因为CRegisterView要负责打开和关闭登录数据对话框,并将从对话框中输入的数据在视图中输出。

然后,请读者在RegisterView.cpp文件的开头加入下面一行

#include "RegisterDialog.h"

最后,按清单5.4修改程序。

清单5.4 OnEditRegister函数

void CRegisterView::OnEditRegister()

{

// TODO: Add your command handler code here

CRegisterDialog dlg;

if(dlg.DoModal()==IDOK)

{

CString str;

//获取编辑正文

GetWindowText(str);

//换行

str+="\r\n";

str+="姓名:";

str+=dlg.m_strName;

str+="\r\n";

str+="性别:";

str+=dlg.m_nSex?"女":"男";

str+="\r\n";

str+="年龄:";

CString str1;

//将数据格式输出到字符串对象中

str1.Format("%d",dlg.m_nAge);

str+=str1;

str+="\r\n";

str+="婚否:";

str+=dlg.m_bMarried?"已婚":"未婚";

str+="\r\n";

str+="就业状况:";

str+=dlg.m_nWork?"下岗":"在职";

str+="\r\n";

str+="工作单位:";

str+=dlg.m_strUnit;

str+="\r\n";

str+="单位性质:";

str+=dlg.m_strKind;

str+="\r\n";

str+="工资收入:";

str+=dlg.m_strIncome;

str+="\r\n";

//更新编辑视图中的正文

SetWindowText(str);

}

}

在OnEditRegister函数中,首先构建了一个CRegisterDialog对象,然后调用CDialog::DoModal来实现模态对话框。如果DoModal返回IDOK,则说明用户确认了登录数据的操作,程序需要将录入的数据在编辑视图中输出。程序用一个CString对象来作为编辑正文的缓冲区,CString是一个功能强大的字符串类,它的最大特点在于可以存储动态改变大小的字符串,这样,用户不必担心字符串的长度超过缓冲区的大小, 使用十分方便。

在输出数据时,程序首先调用CWnd::GetWindowText获得编辑正文,这是一个多行的编辑正文。CWnd::GetWindowText用来获取窗口的标题,若该窗口是一个控件,则获取的是控件内的正文。CRegisterView是CEditView的继承类,而CEditView实际上包含了一个编辑控件,因此在CRegisterView中调用GetWindowText获得的是编辑正文。

然后,程序在该编辑正文的末尾加入新的数据。在程序中大量使用了CString类的重载操作符“+=”,该操作符的功能是将操作符右侧字符串添加到操作符左侧的字符串的末尾。注意在多行编辑控件中每行末尾都有一对回车和换行符。在程序中还调用了

CString::Format来将数据格式化输出到字符串中,Format的功能与sprintf类似。最后,调用CWnd::SetWindowText来更新编辑视图中的正文。

编译并运行Register,打开登录数据对话框,输入一些数据试试。现在,Register已经是一个简易的数据库应用程序了,它可以将与就业情况有关的数据输出到一个编辑视图中。用户可以编辑视图中的正文,并将结果保存在文本文件中。

5.3.6处理控件通知消息

虽然Register已经可以登录数据了,但读者会很快会发现该程序还有一些不完善的地方:

登录完一个人的数据后,对话框就关闭了,若用户有很多人的数据要输入,则必须频繁地打开对话框,很不方便。在登录数据时,应该使对话框一直处于打开状态。

登录数据对话框分个人情况和单位情况两组,若被调查人是下岗职工,则不必输入单位情况。程序应该能够对用户的输入及时地作出反应,即当用户选择了“下岗”单选按钮时,应使单位情况组中的控件禁止。一个禁止的控件呈灰色示,并且不能接收用户的输入。

要解决上述问题,就必须对控件通知消息进行处理。当控件的状态因为输入等原因而发生变化时,控件会向其父窗口发出控件通知消息。例如,如果用户在登录数据对话框中的某一按钮(包括普通按钮、检查框和单选按钮)上单击鼠标,则该按钮会向对话框发送

BN_CLICKED消息。对话框根据按钮的ID激活相应的BN_CLICKED消息处理函数,以对单击按钮这一事件作出反应。通过对按钮的BN_CLICKED消息的处理,我们可以使登录数据对话框的功能达到上述要求。

首先,让我们来解决第一个问题。我们的设想是修改原来的“确定(Y)”按钮,使得当用户点击该按钮后,将数据输出到视图中,并且对话框不关闭,以便用户输入下一个数据。请读者按下面几步进行修改。

修改登录数据对话框的“确定(Y)”按钮,使该按钮的标题变为“添加(&A)”,ID变为

IDC_ADD。这样,当用户点击该按钮后,对话框会收到BN_CLICKED消息。由于这个BN_CLICKED 消息对应的按钮ID不是IDOK,不会触发OnOK消息处理函数,因此不会关闭对话框。

为按钮IDC_ADD的BN_CLICKED消息创建消息处理函数。创建的方法是进入ClassWizard 后,选Message Maps页并在Class name栏中选择CRegisterDialog,然后在Object IDs 栏中选择IDC_ADD,在Messages栏中双击BN_CLICKED。在确认使用缺省的消息处理函数名OnAdd后,按回车键退出ClassWizard。

OnAdd要向编辑视图输出正文,就必须获得一个指向CRegisterView对象的指针以访问该对象。为此,请在CRegisterDialog类的说明中加入下面一行

Cwnd* m_pParent;

注意不要加在AFX注释对中。

为实现IDC_ADD按钮的功能,请按清单5.5和清单5.6修改程序。主要的改动是把原来由CRegiserView::OnEditRegister完成的在视图中输出数据的任务交给CRegisterDialog::OnAdd来完成。

清单5.5 CRegisterView::OnEditRegister函数

void CRegisterView::OnEditRegister()

{

// TODO: Add your command handler code here

CRegisterDialog dlg(this);

dlg.DoModal();

}

清单5.6 CRegisterDialog类的部分源代码

CRegisterDialog::CRegisterDialog(CWnd* pParent /*=NULL*/)

: CDialog(CRegisterDialog::IDD, pParent)

{

//{{AFX_DATA_INIT(CRegisterDialog)

. . . . . .

//}}AFX_DATA_INIT

m_pParent=pParent;

}

void CRegisterDialog::OnAdd()

{

// TODO: Add your control notification handler code here

//更新数据

UpdateData(TRUE);

//检查数据是否有效

if(m_strName=="" || m_nSex<0 || m_nWork<0 || m_strUnit==""

|| m_strKind=="" || m_strIncome=="")

{

AfxMessageBox("请输入有效数据");

return;

}

CString str;

//获取编辑正文

m_pParent->GetWindowText(str);

//换行

str+="\r\n";

str+="姓名:";

str+=m_strName;

str+="\r\n";

str+="性别:";

str+=m_nSex?"女":"男";

str+="\r\n";

str+="年龄:";

CString str1;

//将数据格式输出到字符串对象中

str1.Format("%d",m_nAge);

str+=str1;

str+="\r\n";

str+="婚否:";

str+=m_bMarried?"已婚":"未婚";

str+="\r\n";

str+="就业状况:";

str+=m_nWork?"下岗":"在职";

str+="\r\n";

str+="工作单位:";

str+=m_strUnit;

str+="\r\n";

str+="单位性质:";

str+=m_strKind;

str+="\r\n";

str+="工资收入:";

str+=m_strIncome;

str+="\r\n";

//更新编辑视图中的正文

m_pParent->SetWindowText(str);

}

CRegisterDialog的构造函数有一个参数pParent,该参数是一个指向CWnd对象的指针,用于指定对话框的父窗口或拥有者窗口。在CRegisterView:: OnEditRegister函数中,在构建CRegisterDialog对象时指定了this参数,this指针指向CRegisterView对象本身。这样在调用CRegisterDialog的构造函数时,this指针值被赋给了CRegisterDialog的成员m_pParent。OnAdd函数可利用m_pParent来访问对话框的拥有者即CRegisterView对象。

CRegisterDialog::OnAdd将被调用。在OnAdd中,首先调用了UpdateData(TRUE)以把数据从控件传给对话框的数据成员变量。然后,程序要对数据的有效性进行检查,如果输入的数据不完全有效,则会显示一个消息对话框,提示用户输入有效的数据。接下来进行的工作是在视图中输出数据,这部分代码与清单5.4类似,读者应该比较熟悉了。

完成上述工作后,登录数据对话框就变得较为实用了。打开对话框后,用户可以方便地输入多人的数据,只有按了取消按钮后,对话框才会关闭。

接下来让我们来解决第二个问题。解决该问题的关键在于当用户点击“在职”或“下岗”单选按钮时,程序要对收到的BN_CLICKED消息作出响应。有些读者可能会想到为两个单选按钮分别创建BN_CLICKED消息处理函数,这在只有两个单选按钮的情况下是可以的,但如果一组内有多个单选按钮,则分别创建消息处理函数就比较麻烦了。利用MFC提供的消息映射宏ON_CONTROL_RANGE可以避免这种麻烦,该映射宏把多个ID连续的控件发出的消息映射到同一个处理函数上。这样,我们只要编写一个消息处理函数,就可以对“在职”和“下岗”两个单选按钮的BN_CLICKED消息作出响应。ClassWizard不支持ON_CONTROL_RANGE宏,所以我们必须手工创建单选按钮的消息映射和消息处理函数。

首先,在CRegisterDialog类的头文件中加入消息处理函数的声明,该函数名为OnWorkClicked,如清单5.7所示。

清单5.7 BN_CLICKED消息处理函数OnWorkClicked的声明

protected:

void OnWorkClicked(UINT nCmdID);

// Generated message map functions

//{{AFX_MSG(CRegisterDialog)

virtual BOOL OnInitDialog();

afx_msg void OnAdd();

//}}AFX_MSG

然后,在CRegisterDialog类的消息映射中加入ON_CONTROL_RANGE映射,如清单5.8所示。ON_CONTROL_RANGE映射的形式是ON_CONTROL_RANGE

清单5.8 在CRegisterDialog类的消息映射中加入ON_CONTROL_RANGE映射

BEGIN_MESSAGE_MAP(CRegisterDialog, CDialog)

//{{AFX_MSG_MAP(CRegisterDialog)

ON_BN_CLICKED(IDC_ADD, OnAdd)

//}}AFX_MSG_MAP

ON_CONTROL_RANGE(BN_CLICKED, IDC_WORK, IDC_WORK1, OnWorkClicked)

END_MESSAGE_MAP()

ON_CONTROL_RANGE消息映射宏的第一个参数是控件消息码,第二和第三个参数分别指明了一组连续的控件ID中的头一个和最后一个ID,最后一个参数是消息处理函数名。如果读者是按表5.2的顺序放置控件的则IDC_WORK和IDC_WORK1应该是连续的。这样,无论用户是在IDC_WORK还是在IDC_WORK1单选按钮上单击,都会调用OnWorkClicked消息处理函数。

提示:如果不能确定两个ID是否是连续的,请用File->Open命令打开resource.h文件,在该文件中有对控件ID值的定义。如果发现两个ID是不连续的,读者可以改变对ID 的定义值使之连续,但要注意改动后的值不要与别的ID值发生冲突。

最后,在CRegisterDialog类所在CPP文件的最后插入消息处理函数CRegisterDialog::OnWorkClicked,如清单5.9所示。

清单5.9 CRegisterDialog::OnWorkClicked消息处理函数

void CRegisterDialog::OnWorkClicked(UINT nCmdID) {

//判断“在职”单选按钮是否被选中

if(IsDlgButtonChecked(IDC_WORK)){

//使控件允许

GetDlgItem(IDC_UNIT)->EnableWindow(TRUE);

GetDlgItem(IDC_KIND)->EnableWindow(TRUE);

GetDlgItem(IDC_INCOME)->EnableWindow(TRUE);

}

else{

//清除编辑框的内容并使之禁止

GetDlgItem(IDC_UNIT)->SetWindowText("");

GetDlgItem(IDC_UNIT)->EnableWindow(FALSE);

//使组合框处于未选择状态并使之禁止

CComboBox *pComboBox=(CComboBox *)GetDlgItem(IDC_KIND);

pComboBox->SetCurSel(-1);

pComboBox->EnableWindow(FALSE);

//使列表框处于未选择状态并使之禁止

m_ctrlIncome.SetCurSel(-1);

m_ctrlIncome.EnableWindow(FALSE);

}

}

OnWorkClicked函数判断“在职”单选按钮是否被选中。若该按钮被选中,则使单位情况组中的控件允许,若该按钮未被选中,则说明“下岗”按钮被选中,这时应使控件禁止,清除编辑框中的正文,并且使组合框和列表框处于未选中状态。

在OnWorkClicked函数中主要调用了下列函数:

CWnd::IsDlgButtonChecked函数,用来判断单选按钮或检查框是否被选择,该函数的声明为

UINT IsDlgButtonChecked(int nIDButton) const;

参数nIDButton为按钮的ID。若按钮被选择,则函数返回1,否则返回0,若按钮处于不确定状态,则返回值为2。

CWnd::GetDlgItem函数,用来获得指向某一控件的指针,该函数的声明为

CWnd* GetDlgItem(int nID) const;

参数nID为控件的ID。该函数返回一个指定控件的CWnd对象指针,通过该指针,程序可以对控件进行控制。

CWnd::EnableWindow函数,该函数使窗口允许或禁止,禁止的窗口呈灰色显示,不能接收键盘和鼠标的输入。该函数的声明是

BOOL EnableWindow( BOOL bEnable = TRUE );

若参数bEnable的值为TRUE,则窗口被允许,若bEnable的值为FALSE,则窗口被禁止。

CListBox::SetCurSel和CComboBox::SetCurSel函数功能类似,用来使列表中的某一项被选中,选中的项呈高亮度显示。函数的声明是

int SetCurSel(int nSelect);

参数nSelect指定了新选项的索引,第一项的索引值为0,若nSelect的值为-1,那么函数将清除以前的选择,使列表处于未选择状态。

有时,需要将GetDlgItem返回的CWnd指针强制转换成控件对象的指针,以便调用控件对象专有的成员函数对控件进行控制。例如,在程序中GetDlgItem(IDC_KIND)返回的指针被强制转换成CComboBox类型,只有这样,才能调用CComboBox::SetCurSel成员函数。

为了对控件进行查询和控制,在程序中采用了两种访问控件的方法。一种方法是直接利用ClassWizard提供的控件对象,例如m_ctrlIncome列表框对象。另一种方法是利用CWnd 类提供的一组管理对话框控件的成员函数,例如程序中用到的GetDlgItem和

IsDlgButtonChecked。这两种方法是在对话框内访问控件的常用方法,读者都应该掌握。表5.5列出了管理对话框控件的Cwnd成员函数。

表5.5 用来管理对话框控件的CWnd成员函数

5.4 非模态对话框

5.4.1 非模态对话框的特点

与模态对话框不同,非模态对话框不垄断用户的输入,用户打开非模态对话框后,仍然可以与其它界面进行交互。

非模态对话框的设计与模态对话框基本类似,也包括设计对话框模板和设计CDialog类的派生类两部分。但是,在对话框的创建和删除过程中,非模态对话框与模态对话框相比有下列不同之处:

?非模态对话框的模板必须具有Visible风格,否则对话框将不可见,而模态对话框则无需设置该项风格。更保险的办法是调用CWnd::ShowWindow(SW_SHOW)来显示对话框,而不管对话框是否具有Visible风格。

?非模态对话框对象是用new操作符在堆中动态创建的,而不是以成员变量的形式嵌入到别的对象中或以局部变量的形式构建在堆栈上。通常应在对话框的拥有者窗口类内声明一个指向对话框类的指针成员变量,通过该指针可访问对话框对象。

?通过调用CDialog::Create函数来启动对话框,而不是CDialog::DoModal,这是模态对话框的关键所在。由于Create函数不会启动新的消息循环,对话框与应用程序共用同一个消息循环,这样对话框就不会垄断用户的输入。Create在显示了对话框后就立即返回,而DoModal是在对话框被关闭后才返回的。众所周知,在MFC程序

MFC知识点(自己整理的,只供参考)

知识点:不是很全面,只供参考 第一章 Windows应用程序使用的界面是由各种图形元素组成的图形界面(GUI)。 Windows提供了大量预定义的用C语言编写的函数,这些函数就叫做API(Application Programming Interface)函数。 在Windows应用程序中,存在着许多与DOS应用程序不同的复杂对象,例如窗口、按钮、滚动条等等。Windows把为这种复杂对象所定义的标识叫做句柄。 常用的句柄类型:HWND 窗口句柄,HDC 图形设备环境句柄,HINSTANCE 当前程序应用实例句柄,HBITMAP 位图句柄,HICON 图标句柄,HCURSOR 光标句柄,HBRUSH 画刷句柄,HPEN 画笔句柄,HFONT 字体句柄,HMENU 菜单句柄,HFILE 文件句柄 事件的描述是一个消息 消息的结构: typedef struct tagMSG { HWND hwnd; //产生消息的窗口句柄 UINT message;//消息的标识码 WPARAM wParam;//消息的附加信息1 LPARAM lParam;//消息的附加信息2 DWORD time; //消息进入消息队列的时刻 POINT pt; //表示发送该消息时鼠标的位置 }MSG; 消息循环: while(GetMessage(&msg,NULL,NULL,NULL))//系统处理了消息后返回 { TranslateMessage(&msg);//把键盘消息翻译成字符消息 DispatchMessage(&msg);//把消息派发给Windows系统 创建窗口的三个步骤: 注册窗口类: RegisterClass(&wc); 创建窗口: hwnd=CreateWindow( lpszClassName, "Windows", WS_OVERLAPPEDWINDOW, 120,50,800,600, NULL, NULL, hInstance, NULL); 显示窗口: ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); 大题:用函数封装Windows程序(P16) 第二章

VC 中自己创建对话框方法

VC中自己创建对话框的方法 这里讲在VC中不需要打开MFC工程,通过代码直接创建一个对话框,我看这个对话框比MFC的漂亮多了,而且要写会代码不需要研究MFC就直接开发新的工程. 先打开VC++ 6.0 版本, 第一步:创建一个工程名为:Main Dialog 的Win32 Application。创建过程如下: 打开File菜单中New,选自Win32 Application,工程名为:Main Dialog,点击OK,再选自A simple Win32 application。点击Finish,再点击OK.(见图1) 第二步:创建资源脚本。再打开File菜单中New,选自File选项的Resource Script(就是资源脚本),文件名为Dialog,点击OK。

(见图2) 第三步:插入对话框。刚才建立的脚本Dialog显示为Dialog.rc,就在Dialog.rc上面点击鼠标右键Insert(插入)Resource中选自插入Dialog(对话框),点击New(新建),这样对话框插入完毕。(见图3)

第四步:添加resource.h。我们把第四步插入的对话框ID改为IDD_MAIN ,在FileView中有个Header Files的文件,上面点击右键,选择Add Files to Folder...(添加文件到目录),弹出一个工程目录窗口,中间找到resource.h,然后OK了(添加)。(见图4)

第五步:复制代码。双击Main Dialog.cpp,我们写代码的位置出现了(见图5),那里有几行代码,把它们全部删掉,下面已经准备好的代码全部复制到那里,编译,执行,您的是否成功了? #include "stdafx.h" #include "resource.h" #include BOOL WINAPI Main_Proc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); BOOL Main_OnInitDialog(HWND hwnd,HWND hwndFocus,LPARAM lParam); void Main_OnCommand(HWND hwnd,int id,HWND hwndCtl,

MFC入门--对话框实例

MFC入门--对话框实例 实例1 目的:设计一个基于对话框的程序,界面上有一个“延迟6秒”的按钮,点击后,程序主窗口在6秒内无法拖动。 关键点:MFC程序入门、线程与进程、消息机制 操作过程: 1-新建项目,选择MFC AppWizard (exe),命名项目为“SingleThread”。如图: (注:关于各项目类型的说明,请参见文件“VC功能简介.ppt”的第8页) 2-选择“Dialog based”,点击Finish,仔细观察项目信息。

3-在资源视图内对主对话框添加静态文本:“我的第一个MFC程序”和“演示耗时的单线程”,继而添加一个按钮,按钮现实文字“延迟6秒”,如图: 4-在资源视图内,双击“延时6秒”按钮,为其添加BN_CLICKED消息(按下按钮时发出的消息)的响应函数OnButton1()。在其中添加代码: Sleep(6000); 请根据老师对程序的讲解,思考如下问题: 1.类的继承:三个的类(CAboutDlg、CSingleThreadApp、CStringThreadDlg) 的继承轨迹是怎样的? 2.程序的入口在哪里?有没有类似Win32 Application中对于WM_CREATE的 处理? 3.三个类的对象的关系。 4.消息如何映射?

设计一个基于对话框的程序,开始运行后,每两秒弹出一个消息框。 关键点:MFC程序入门;定时器的建立、使用与删除;消息映射 操作过程: 1-新建项目,选择MFC AppWizard (exe),命名项目为“Test”。 2-选择“Dialog based”。 3-在BOOL CTestDlg::OnInitDialog()函数中添加 SetTimer(1,2000,NULL); // 启动定时器 4-通过ClassWizard给对话框添加WM_DESTROY的响应函数。如图: 在其中添加代码: KillTimer(1); 5-通过ClassWizard给对话框添加WM_TIMER的响应函数。在其中添加代码: if(nIDEvent==1) { ::MessageBox(0,"嘿嘿","你点啊!!",MB_OK); } 请根据老师对程序的讲解,思考如下问题: 1.MFC下与Win32 Application下定时器的使用有什么不同,又有什么相同之 处?

MFC对话框程序中的各组件常用方法

MFC对话框程序中的各组件常用方法: Static Text: 将ID号改成唯一的一个,如:IDC_XX,然后进一次类向导点确定产生这个ID,之后更改Caption属性: GetDlgItem(IDC_XX)->SetWindowText(L"dsgdhfgdffd"); 设置字体: CFont *pFont = new CFont; pFont->CreatePointFont(120,_T("华文行楷")); GetDlgItem(IDC_XX)->SetFont(pFont); Edit Control: 设置文本: SetDlgItemText(IDC_XX,L"iuewurebfdjf"); 获取所有输入: 建立类向导创建一个成员变量(假设是shuru1,shuru2……)类型选value,变量类型任选。 UpdateData(true); GetDlgItem(IDC_XX)->SetWindowText(shuru1); 第一句更新所有建立了变量的对话框组件,获取输入的值。第二句将前面的IDC_XX的静态文本内容改为shuru1输入的内容。 若类型选用control: 1.设置只读属性: shuru1.SetReadOnly(true); 2.判断edit中光标状态并得到选中内容(richedit同样适用) int nStart, nEnd; CString strTemp; shuru1.GetSel(nStart, nEnd); if(nStart == nEnd) { strTemp.Format(_T(" 光标在%d" ), nStart); AfxMessageBox(strTemp); } else { //得到edit选中的内容 shuru1.GetWindowText(strTemp); strTemp = strTemp.Mid(nStart,nEnd-nStart); AfxMessageBox(strTemp); } 其中nStart和nEnd分别表示光标的起始和终止位置,从0开始。strTemp.Format 方法用于格式化字符串。AfxMessageBox(strTemp)显示一个提示对话框,其内容是字符串strTemp。 strTemp = strTemp.Mid(nStart,nEnd-nStart)返回一个被截取的字符串,从nStart开始,长度为nEnd-nStart。如果nStart == nEnd说明没有选择文本。 注:SetSel(0,-1)表示全选;SetSel(-1,i)表示删除所选。

(适合初学者)MFC基础教程

Visual C++/MFC初学教程 目录 +-- 第一章VC入门 |------ 1.1 如何学好VC |------ 1.2 理解Windows消息机制 |------ 1.3 利用Visual C++/MFC开发Windows程序的优势|------ 1.4 利用MFC进行开发的通用方法介绍 |------ 1.5 MFC中常用类,宏,函数介绍 +-- 第二章图形输出 |------ 2.1 和GUI有关的各种对象 |------ 2.2 在窗口中输出文字 |------ 2.3 使用点,刷子,笔进行绘图 |------ 2.4 在窗口中绘制设备相关位图,图标,设备无关位图|------ 2.5 使用各种映射方式 |------ 2.6 多边形和剪贴区域 +-- 第三章文档视结构 |------ 3.1 文档视图框架窗口间的关系和消息传送规律 |------ 3.2 接收用户输入 |------ 3.3 使用菜单

|------ 3.4 文档,视,框架之间相互作用 |------ 3.5 利用序列化进行文件读写 |------ 3.6 MFC中所提供的各种视类介绍 +-- 第四章窗口控件 |------ 4.1 Button |------ 4.2 Static Box |------ 4.3 Edit Box |------ 4.4 Scroll Bar |------ 4.5 List Box/Check List Box |------ 4.6 Combo Box/Combo Box Ex |------ 4.7 Tree Ctrl |------ 4.8 List Ctrl |------ 4.9 Tab Ctrl |------ 4.A Tool Bar |------ 4.B Status Bar |------ 4.C Dialog Bar |------ 4.D 利用AppWizard创建并使用ToolBar StatusBar Dialog Bar |------ 4.E General Window |------ 4.F 关于WM_NOTIFY的使用方法 +-- 第五章对话框 |------ 5.1 使用资源编辑器编辑对话框 |------ 5.2 创建有模式对话框

Visual C++基于对话框的MFC应用程序---简单的时钟实例实验一

1.1 创建对话框的应用程序 1.使用AppWizard创建应用程序框架 首先,创建一个对话框应用程序,其工程文件名为:ch1.dsp。具体步骤如下: (1)启动Visual C++ 6.0,在File菜单中选择new菜单项;(2)在new对话框的Project页中选择 MFC AppWizard(exe)选项,在Project name框中输入:ch1,并在Location 框中指定希望的目录路径,编译系统生成的各种文件将会存放在该目录下,然后点击[OK]按钮 (3)MFC AppWizard-Step1 中选择Dialog based 选项,MFC AppWizard-Step2 到MFC AppWizard-Step4中取默认选项;(4)进入VC对话框设计界面后,选中 [TODO:在这里设置对话控制。]静态框并按del键删除该框,选中[取消]按钮并按del键删除该按钮; (5)将[确认]按钮拖曳到对话框的下方中间。生成的对话框设计窗口(如图1-1所示)。 图1-1

2.向类中添加系统消息响应函数 Windows应用程序的采用事件触发、消息驱动机制和大量的消息响应函数构成了应用程序的主体。本示例需要用到两个消息响应函数OnCtlColor()和OnTimer(),前者响应窗口消息:WM_CTLCOLOR,后者响应窗口消息:WM_TIMER。关于这两个函数的功能和用法暂且略过,留待后面小节再叙。这里先介绍响应函数加载的方法。 在CCh1Dlg类中添加OnCtlColor( )函数的操作方法如下:(1)打开类向导(MFC ClassWizard)窗口,选择Message Maps 页; (2)选择工程、类和对象标识。在Message Maps页的Project、Class name、Object Ids框中 分别选择:ch1、CCh1Dlg、CCh1Dlg; (3)添加响应函数。在Message Maps页的Messages框中选中并双击窗口消息:WM_CTLCOLOR,此时,消息WM_CTLCOLOR 的响应函数OnCtlColor( )被添加到类向导底部Member Functions框中。 注意,添加OnTimer( )函数的过程与上述过程相似,只是第(3)步选择WM_TIMER消息,而不是WM_CTLCOLOR。 添加完毕后,按[OK]按钮退出类向导。回到项目工作区,在项目工作区窗口展开CCh1Dlg类,可以看到类中添加了OnCtlColor( )和OnTimer( )两个消息响应函数。

MFC对话框向主窗体传递消息机制

对话框向主窗体传递消息,在视图中显示 现举例说明对话框向主窗体传递消息,以及主窗体响应消息的过程。我们拿单文档来说明,我们要实现下列功能:通过对话框,在文本框中输入字符串,在视图中显示刚才输入的字符串。 1、在应用程序向导中选择单个文档,然后完成。我这里的项目名称为mybook 2、在资源视图中,插入一对话框,对话框名称为dlg_wzm。 3、在刚才生成的对话框中插入一文本框,设置好相应的类和变量。为确认按钮生成响应函数。同时在mybook.cpp的BOOL CMyBookApp::InitInstance()函数中让该对话框启动,也就是加入CDlg_wzm dlg; dlg.DoModal();两行程序,当然在前面的要加入#include "dlg_wzm.h"。(详细过程略) 4、下面重点在于点击该对话框的确认按钮向主窗体发送消息。要现定义一个消息名称。

在stdafx.h文件中加入一行: #define WM_MYMESSAGE WM_USER+100 5、在CMainFrame的pulic申明中加入一变量CString wzmstr。目的是为了保存对话框中的字符串的值。在对话框的Onok()函数中: void CDlg_wzm::OnOK() { // TODO: Add extra validation here this->UpdateData(true); CMainFrame* pWnd=(CMainFrame*)AfxGetMainWnd(); //得到父窗体的指针 pWnd->wzmstr=this->m_input_edit; ASSERT(pWnd!=NULL); ::SendMessage(pWnd->GetSafeHwnd(), WM_MYMESSAGE,0,0); //发送消息 //注意WM_MYMESSAGE就是我们前面定义的消息。 //CDialog::OnOK(); } 6、下面我们看看主窗体怎么接受消息。我们要在主窗体中设置消息映射。 在mainfrm.h的protected声明中: afx_msg void OnMyMessage(WPARAM wParam, LPARAM lParam); 在mainfrm.cpp文件中, BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code ! ON_WM_CREATE() ON_MESSAGE(WM_MYMESSAGE,OnMyMessage) //这里是我们加入的。 //}}AFX_MSG_MAP END_MESSAGE_MAP() 然后在mainfrm.cpp的文件最下面加入一个函数: void CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam) { CView *pView=this->GetActiveView(); //得到视图指针 if(pView)

在VC对话框中实现打印和打印预览

在VC对话框中实现打印和打印预览(附实现步骤) 时间:2008-01-27作者:佚名 在一般的软件开发中打印和打印预览是经常要用到的功能,对于VC6.0中的文档/视图(Doc/View)框架,可以很方便的使用缺省的打印和打印预览。但是,如果应用程序是基于对话框的就没有办法利用这种便利。而很多情况下,基于对话框的程序也需要打印和打印预览功能。那该怎么办呢?这正是本文将要解决的问题。 1实现打印 在对话框应用程序中不具备MFC的视和框架交互,要想实现打印和打印预览必须直接获取打印机的设备环境句柄,这时可以设置CPringDialog类中的构造函数的参数,获取打印机的设备环境句柄。利用这个句柄,转换为指针,则按打印流程实现打印任务。 (1)从CFrameWnd类派生出主窗口类CMyFrameWnd加入项目,这个类将作为控制类来实现程序的打印和打印预。 (2)在CMyFrameWnd中加入打印和打印预览相关的函数,为了方便起见,名字和CView视图类中缺省的打印和打印预览虚函数名相同。但这些函数是以成员函数的形式加入的,而不是重载。这里主要介绍Print和OnPrint函数。 Print函数是打印控制函数,由它来弹出打印对话框,取得用户设置信息,如打印机、纸张大小等。还有建立一个打印机DC和设置DOCINFO 结构,该结构包含输入输出文件名及其它一些信息,StartDoc函数要该结构作参数。还要设置打印区域,调用打印函数等 void CMyFrameWnd::Print() { CDC dc; CPrintDialog printDlg(FALSE); if (printDlg.DoModal() != IDOK) //弹出打印对话框,取得用户设置参数 return; dc.Attach(printDlg.GetPrinterDC());

MFC编程基础教程

第1章基于对话框的Windows应用程序 1.简介Windows编程的两种方法,即Windows API编程和MFC编程。 2.基于对话框的应用程序的创建过程: ?建立基于对话框的MFC 应用程序框架; ?放置控件; ?设置控件属性; ?为控件连接变量,即为控件命名; ?添加并且编写消息处理函数。 3.常用基本控件: ?静态文本框:主要用来显示文本信息,不能接受用户输入 ?命令按钮:是最常见的、应用最广泛的一种控件。在程序执行期间,当单击某个命令按钮后就会执行相应的消息处理函数。 ?编辑框:是一个文本编辑区域,用户可以在该区域输入、编辑和显示正文内容。 ?框架:将一组相关的控件框起来,达到标识一组控件的作用。 ?单选按钮:用户在一组单选按钮中最多只能选择一项。当某一项被选定后,其他选项自动变成未选状态。 ?复选框:列出了可供选择的项,用户可根据需要选择其中的一项或多项,各选项之间的状态互不相关。 ?列表框:通过显示多个选项,供用户选择,达到与用户对话的目的。 ?组合框:组合了编辑框和列表框的特性而形成的一种控件。在列表框中列出可供用户选择的项,当用户选定某项后,该项内容自动装入编辑框中。 ?滚动条:通常附在对话框上用来协助观察数据或确定位置,也可以用来作为数据输入的工具。 1.1 Windows编程基础 Windows 应用程序的主要特点是: ?具有标准的图形用户界面。 ?具有与硬件无关的特性。 ?采用“消息传递,事件驱动”的运行机制。 用Visual C++ 编写Windows 应用程序主要有两种方法:一是使用Windows 提供的应用程序接口(Application Programming Interface ,API )函数;二是使用Microsoft 提供的微软基础类(Microsoft Foundation Class ,MFC )。

基于MFC对话框的报表打印和预览功能(推荐文档)

基于MFC对话框的报表打印和预览功能 第一步:在工程中加入实现打印功能的四个文件PrintFrame.h, PringtView.h,PrintFrame.cpp, PrintView.cpp CPrintFrame和CPrintView类是两个个可重用的类,开发者只需要把这两个类对应的四个文件拷贝到工程文件所在目录中(PrintFrame.h, PringtView.h,PrintFrame.cpp, PrintView.cpp),并将这四个文件加入工程,并在需要执行打印功能的代码处加入 #include "PrintFrame.h" #include "PrintView.h" 第二步:添加三个消息响应函数来执行该功能 ON_MESSAGE(WM_BEGIN_PRINTING,OnBeginPrinting) ON_MESSAGE(WM_END_PRINTING,OnEndPrinting) ON_MESSAGE(WM_MY_PRINT,OnMyPrint) 这三个消息响应函数放在.cpp文件的BEGIN_MESSAGE_MAP(CReportDlg, CDialog)与END_MESSAGE_MAP()之间,如下:BEGIN_MESSAGE_MAP(CReportDlg, CDialog) //{{AFX_MSG_MAP(CReportDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, OnButton1) ON_MESSAGE(WM_BEGIN_PRINTING,OnBeginPrinting) ON_MESSAGE(WM_END_PRINTING,OnEndPrinting) ON_MESSAGE(WM_MY_PRINT,OnMyPrint) ON_BN_CLICKED(IDC_BUTTON2, OnButton2) //}}AFX_MSG_MAP END_MESSAGE_MAP() 其中OnMyPrint是跟具体要打印什么内容有关的开发人员要重点完成的代码,可以打印表格,图片,数据,只要GDI绘图可以进行的操作在这里都可以完成。由于打印预览的一部分工作在CView类里完成,因此在用户程序中只需要相应 WM_MY_PRINT消息就可以执行打印预览的功能,而不需要另外编写打印预览代码。 第三步: 建立一个CPrintFrame的对象,设该对象的指针为pFrame,并将对话框的指针传给该对象的m_pCallerDlg,即pFrame->m_pCallerDlg = this;

创建基于对话框的MFC工程(详细图示)

实例001 如何创建基于对话框的MFC工程 《Visual C++开发实战1200例(第I卷)》本书以开发人员在项目开发中经常遇到的问题和必须掌握的技术为中心,介绍了应用Visual C++进行程序开发各个方面的知识和技巧,主要包括编程基础、界面设计、应用程序控制和图形图像。本节为大家介绍实例001 如何创建基于对话框的MFC工程。 AD: 第1章开发环境 工程创建 开发环境设置与使用 程序调试 1.1 工程创建 实例001 如何创建基于对话框的MFC工程 要使用Visual C++开发软件,首先要创建一个工程,而基于对话框的MFC工程则是用户广泛使用的工程。图1.1将是一个新创建的基于对话框的MFC工程。本实例将介绍如何创建基于对话框的MFC工程。

( New窗口的Projects选项卡中选择MFC AppWizard[exe](MFC应用程序向导)选项,在Project name文本框中输入创建的工程名"Hello",在Location文本

(2)单击OK按钮,弹出MFC AppWizard-Step 1窗口,如图1.3所示。 在MFC AppWizard-Step1窗口中可以指定生成框架的类型。 Single document:生成单文档应用程序框架。 Multiple documents:生成多文档应用程序框架。 Dialog based:生成基于对话框的应用程序框架。 Document/View architecture support:选中该复选框,允许生成文档/视图和非文档/视图结构程序。 (3)本实例选中Dialog based单选按钮,创建一个生成基于对话框的应用程序。单击Next按钮,弹出MFC AppWizard-Step 2 of 4窗口,如图1.4所示。

MFC中在一个对话框中弹出另一个对话框

在一个对话框中点按一个按钮弹出另外一个对话框。 弹出的对话框可以是模态和非模态两种,简单点讲,模态对话框就是在弹出的对话框没有关闭之前,是不能操作父对话框的。非模态可以。 这里介绍建立模态对话框。 在建立的时候可以有两种形式,一种是直接新建,一种是将已有的对话框整合添加进来。 (我是在WinCE平台下。也是类似MFC的) 第一种方式:新建弹窗 操作步骤 首先按步骤建立一个简单的对话框,并添加按钮。 然后点击Dialog 添加资源 选择Dialog 新建

此时会出现新建好的对话框,右击选择属性可以修改名称。 设计新建的对话框 在对话框上右击选择添加类

填写类名称,点击完成 此时在解决方案资源管理器视图中就会有新建的类,源文件及头文件

将这个头文件包含到主对话框的头文件中。 然后就是调用关系的产生, 双击主窗口在中的按钮,添加相应的处理函数 此时调试运行,点“刀”按钮,就会弹出设计好的刀的对话框。 当然,刀对话框中的设计就是走原来熟悉的路了。 另外一个键“剑” 也是同样的步骤。 这样弹出的对话框有个问题,就是感觉弹出的对话框缩放了,字体变小了。在对话框上右击选择属性就可以看见设置字体的选项了,修改字体即可。

下来介绍第二种方式,添加现有的窗口。第一步:同样按部就班的建立好基本工程。编译一下(F7) 第二步:拷贝文件 首先在当前工程目录下新建一个文件夹用来存放原有工程源码

需要拷贝下面选中的这几个文件。拷贝到新建的这个文件夹下。由于现有工程中有resource.h文件,所以需要提前改一下名称,相应的WifiConfig.rc文件中有调用到这个文件,所以也要修改。用记事本打开.rc文件,将#include“Resource.h” 改为#include “Resource_2.h”(如果是准备新建文件夹来组织代码的话就可以不用改。就像下面这样,其实可以不用改)将这几个文件拷贝到新建的文件夹下。 还需要将原有工程res目录下的图标拷贝到现在工程的res目录下 第三步:添加文件到工程 首先是资源文件添加 现有项,找到WiFI2Uart目录下的.rc文件。确定。

简易MFC对话框程序设计教程

简易MFC对话框程序设计教程 天津大学仁爱学院信息系杨晓龙 我们之前所学习的C语言是一种面向过程的语言,重点在于程序或算法执行过程,提供那些过程才能实现程序,每一个操作都由我们自己完成。C++是一种面向对象的语言。对象是一个封装体,是一个实例,它里面不仅封装了程序运行时所需变量,更重要的是它还封装了程序运行所需操作即函数,其实真正定义它们的是一种叫“类”的数据结构,不过要引用里面的数据和操作必须通过类所定义的对象。这样做的好处是可以把经常使用的,属于同一类型的数据和操作包含在类当中,在编程时通过该类所实例化的对象调用它们(对象避免了重复,而且对象可以代表一种变量、一个实例或某个控件),简化了代码,提高了代码的复用性,增强了程序的可移植性,降低了错误发生率,摆脱了每次编写程序都要编写大量代码的麻烦。MFC(Microsoft Foundation Class)是微软提供给编程者的基础类库,它里面包含了创建对话框程序所需的各种类,在向导的帮助下,它会自动生成一些代码,我们只需调用它里面的少量成员函数便可完成对话框的创建和对话框程序的编程,如果让我们自己编写将是浩大而艰难的工程。MFC将常用的几乎所有的有关对话框的函数和变量封装起来,使我们避免了编写复杂而且重复的代码。 用C语言所编写的程序是DOS程序,只能在黑乎乎的DOS界面下运行,但C语言是C++的基础,而C++又是MFC的基础,用MFC编写的是windows应用程序有对话框,所以要回MFC 编程得先学C语言和C++才能学MFC。以下将以编写求三角形面积的程序为例说明简单MFC 程序的制作方法。 打开vc6.0,文件—新建—选择MFC AppWizard(exe),工程名称“三角形面积计算器”—确定—选择“基本对话框”,此时即可点“完成”,也可点下一步,直到出现询问“您希望使用MFC库吗?”若选择“作为共享的DLL”,则程序在未安装vc6.0的电脑上无法运行;若选择“作为静态的DLL”,则程序在未安装vc6.0的电脑上也能运行。此后一直点确定即可。 点击“完成”后出现由向导创建的基本对话框,在对话框上点右键—属性,可更改对话框标题和字体。在右侧选择组件,先插入三个编辑框作为三角形三边长,在插入一按钮发出计算命令,然后再插入一编辑框作为面积输出。在每一个编辑框旁配上静态文本说明,修改按钮标题。在vc6.0左侧的资源视图中选中关于对话框,可修改版本信息。至此对话框主体设计完成。 以下是程序最关键的部分。我们拥有C语言的基础,用C语言编写三角形面积代码(算法)不是问题,问题在于如何将编辑框中输入的数据传给算法中的变量以及如何使计算完成的结果输出到编辑框。实现这一数据交换(传输)有七中方法,其中最简单、最直观、最实用的方法是将编辑框与算法中的变量其的关联。步骤如下:选中对应编辑框,右键选择建立类向导,选择“Member Variables(成员变量)”选项卡,选择要关联变量的控件ID号,再点击“Add Variable(添加变量)”,设定变量名如“m_sizeA”,在Variable Type(变量类型)中选择float(不同程序视所需变量类型确定),OK。同样方法,将其他两边和面积分别关联变量。这样就使编辑框分别与各变量取得了关联,以后可认为编辑框和变量是一样的,对变量的任何操作都会反映到编辑框中,接下来我们就可以像编C程序一样编写代码了。可是代码应该写在什么地方呢,程序在什么时候执行呢?我们的目的是在按下计算按钮后程序执行,所以还需对按钮进行设定,让按钮被按下后执行程序。这个过程被称作消息捕获,操作系统捕获到“点击”的消息后将信息传给应用程序,应用程序便转入执行算法。在按钮上点击右键,选择“建立类向导”,选择“Message Maps(消息地图)”选项卡,选中按钮ID号,在“Messages(消息)”中选中“BN_CLICKED(按钮单击)”消息响应方式(因为按钮可以有单击、双击、移动等多种操作,所以对应有多种消息响应方式,即选择:当对按钮执行怎样的操作后执行消息响应函数),然后点击“Add Function(添加消息响应函数)”添加响应消息的函数或操作,也就是指当按钮被按下后要做什么,在弹出的对话框中可以更改函数名,确定后点击“Edit Code(编辑代码)”便自动转入消息响应函数中,我们就可以在这里写我们的算法代码了。代码如下:

MFC简单的登录对话框

登录对话框 我们利用MFC编写一个简单的登录对话框。主窗体是单文档界面。程序运行的时候,先弹出一个简单的登录对话框,输入用户名和密码后主窗体显示出来。 1、开打VC++6.0。点击文件,新建,点击工程中的MFC AppWizard(exe),在右边选择工程保存的位置,并且为工程取好名字。 2、点击确定后,选择单个文档,你可以一直点击下一步,直到完成,或者在这里直接点击完成即可,完成后界面如下。 3、点击工具栏中的“!”号试着编译运行一次,看是否有问题。如果没有问题,我们继续。点击左边的ResourceView,在Dialog上面鼠标右键单击弹出一弹出框,单击Insert Dialog。

4、在右边新增的对话框中,适当改变窗口大小,加入静态文本框和文本编辑框。 输入用户名:。然后回车

同样在下面的第二个静态文本框的属性标题改为:输入密码:。然后回车。 6、在第一个文本编辑框上右键单击,点击属性,把ID框中的IDC_EDIT1改为容易理解的名字,如:IDC_EDIT_NAME,注意前面的IDC_EDIT最好不要去掉,这样容易见名而知义。同样,对第二个文本编辑框的属性中的IDC_EDIT2改为:IDC_EDIT_PWD 7、在对话框上的任何空白的地方右键单击,点击建立类向导。

然后弹出 选择建立Create a new class,点击OK。 这是为这个对话框创建一个新的类。在Name中,为该对话框类取个名字:CDlg_login。下面的Base class以及Dialog ID不要随便改动。然后点击OK。这样新的类CDlg_login就与本对话框建立起了联系。

MFC对话框几个对话框程序例子建立对话框与相应程序相关联

MFC对话框和对话框类几个对话框程序例子建立对话框与相应的程序相关联如何建立对话框与相应的程序相关联: 在MFC中,对资源的操作都是建立相关的类来完成的; 所以我门先NEW 一个对话框资源然后建立他的类与相应的应用程序相关联就可以; 步骤: 1 NEW 一个对话框资源 2 在资源上选择 Classwarrzd上创建一个新的类(或在资源上双击左键) 3 起名字!(注意文件名将会去掉C 例如我门的名字叫 CDaiDlg那么文件名是 DaiDlg); 对话框的俩种类型: 1 模态对话框(特性:当建立模态对话框时,将不允许用户点击对话框以外的控件后应用程序本身,也就是说当模态对话框建立时应用程序停止运行而只运行对话框,所以模态对话框是可以使用局部变量的定义方法的!) 模态对话框是比较方便的一种对话框~建立函数: int CDialog::DoMadol() //注意他是CDialog类成员也就是说想使用先建立一个 CDialog 对象吧 如果我门想要在View类中建立一个 CDialog对象不要忘了要在View的Cpp 文件中包含 CDialog.h 2 非模态对话框(特性与模态的相反) 使用成员函数 BOOL CDialog::Create( UINT nIDTemplate, CWnd* pParentWnd = NULL ); nIDTemplate 为对话框的ID号 pParentWnd 拥有这个对话框的对象指针,如果是NULL 为默认的主应用窗口也就是 Frame应用窗口 注意如果我门在使用Create创建非模态对话框时要调用一个函数来显示这个对话框 CWnd::ShowWindow(SW_SHOW);不仅这样非模态对话框时不能是局部变量!

(完整word版)MFC可收对话框实现

MFC可收缩对话框实现 1可收缩对话框使用 可使用窗口的SetWindowPos()函数,下面重点介绍一下这个函数及具体实现过程。 1.1S etWind owPos函数说明 BOOL SetWindowPos(HWND hWndlnsertAfter, int X,int Y,int cX,int cY,UNIT Flags): 1.1.1hWndInsertAfter 此句柄用于控制对话框在Z轴上的显示顺序,它可以是以下值: ?一个窗口句柄:则对话框会显示在此窗口的下一层; ?HWND_BOTTOM:将窗口置于Z序的底部; ?HWND_DOTTOPMOST:将窗口置于所有非顶层窗口之上(即在所有顶层窗口之后);?HWND_TOP:将窗口置于Z序的顶部。 ?HWND_TOPMOST:将窗口置于所有非顶层窗口之上。即使窗口未被激活窗口也将保持顶级位置。 1.1.2X、Y 相对以客户坐标指定窗口新位置的左边界、上边界;注意,这个X、Y是相对于调整之前窗口的左上角坐标而言的,即(0, 0)表示左上角不变。 1.1.3cX、cY 指定调整后新窗口的宽度和高度;

1.1.4Flags 指定窗口尺寸和定位的标志。它可能为以下值: ?SWP_ASNCWINDOWPOS:如果调用进程不拥有窗口,系统会向拥有窗口的线程发出需求。这就防止调用线程在其他线程处理需求的时候发生死锁。 ?SWP_DEFERERASE:防止产生WM_SYNCPAINT消息。 ?SWP_DRAWFRAME:在窗口周围画一个边框(定义在窗口类描述中)。 ?SWP_FRAMECHANGED:给窗口发送WM_NCCALCSIZE消息,即使窗口尺寸没有改变也会发送该消息。如果未指定这个标志,只有在改变了窗口尺寸时才发送WM_NCCALCSIZE。 ?SWP_HIDEWINDOW:隐藏窗口。 ?SWP_NOACTIV A TE:不激活窗口。如果未设置标志,则窗口被激活,并被设置到其他最高级窗口或非最高级组的顶部(根据参数hWndlnsertAfter设置)。 ?SWP_NOCOPYBITS:清除客户区的所有内容。如果未设置该标志,客户区的有效内容被保存并且在窗口尺寸更新和重定位后拷贝回客户区。 ?SWP_NOMOVE:维持当前位置(忽略X和Y参数)。 ?SWP_NOOWNERZORDER:不改变z序中的所有者窗口的位置。 ?SWP_NOREDRAW:不重画改变的内容。如果设置了这个标志,则不发生任何重画动作。适用于客户区和非客户区(包括标题栏和滚动条)和任何由于窗回移动而露出的父窗口的所有部分。如果设置了这个标志,应用程序必须明确地使窗口无效并区重画窗口的任何部分和父窗口需要重画的部分。 ?SWP_NOREPOSITION:与SWP_NOOWNERZORDER标志相同。 ?SWP_NOSENDCHANGING:防止窗口接收WM_WINDOWPOSCHANGING消息。?SWP_NOSIZE:维持当前尺寸(忽略cx和Cy参数)。 ?SWP_NOZORDER:维持当前Z序(忽略hWndlnsertAfter参数)。 ?SWP_SHOWWINDOW:显示窗口。 对于对话框程序,通常只用设置为:SWP_NOZORDER|SWP_NOMOVE,即保持左上角坐标不变,且保持Z轴顺序不变。

mfc单文档插入对话框

2012/7/18 1.新建一个mfc单文档工程Test. 2.在资源视图中,dialog处右键insert dialog. 3.在新建的dialog上右击,属性-style-child,对话框上双击,新建类 name CCdialod,选择base class为cformview. 4.在cmainframe类上添加变量CSplitterWnd m_wndSplitter选为 protected. 5.classwizard在cmainframe中重载OnCreateClient函数 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { m_wndSplitter.CreateStatic(this,1,2); m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CTestView), CSize(1100, 0), pContext); //CMy039View是视图类 m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CCdialod), CSize(0, 0), pContext); //LDLG是对话框类 SetActiveView((CTestView*)m_wndSplitter.GetPane(0, 0)); //指定类视图 return true; } 6.在TestView.h中添加头文件 #include "TestDoc.h" 7.在mainframe.h中添加 #include "TestView.h" #include "Cdialod.h"

MFC之编写一个简单的登录对话框

编写一个简单的登录对话框 大家好,我们利用MFC编写一个简单的登录对话框。主窗体是单文档界面。程序运行的时候,先弹出一个简单的登录对话框,输入用户名和密码后主窗体显示出来。 1、开打VC++6.0。点击文件,新建,点击工程中的MFC AppWizard(exe),在右边选择工程保存的位置,并且为工程取好名字。 2、点击确定后,选择单个文档,你可以一直点击下一步,直到完成,或者在这里直接点击完成即可,完成后界面如下。 3、点击工具栏中的“!”号试着编译运行一次,看是否有问题。如果没有问题,我们继续。点击左边的ResourceView,在Dialog上面鼠标右键单击弹出一弹出框,单击Insert Dialog。

4、在右边新增的对话框中,适当改变窗口大小,加入静态文本框和文本编辑框。 输入用户名:。然后回车

同样在下面的第二个静态文本框的属性标题改为:输入密码:。然后回车。 6、在第一个文本编辑框上右键单击,点击属性,把ID框中的IDC_EDIT1改为容易理解的名字,如:IDC_EDIT_NAME,注意前面的IDC_EDIT最好不要去掉,这样容易见名而知义。同样,对第二个文本编辑框的属性中的IDC_EDIT2改为:IDC_EDIT_PWD 7、在对话框上的任何空白的地方右键单击,点击建立类向导。

然后弹出 选择建立Create a new class,点击OK。 这是为这个对话框创建一个新的类。在Name中,为该对话框类取个名字:CDlg_login。下面的Base class以及Dialog ID不要随便改动。然后点击OK。这样新的类CDlg_login就与本对话框建立起了联系。

相关文档
最新文档