1. 对话框的基本功能:
1) 对话框是一种特殊的窗口,主要用于响应用户的输入,大部分空间都应放在对话框中;
2) 对话框的创建比普通窗口简单的多,可以直接在资源脚本.rc文件中通过脚本定义;
3) 模态对话框和无模态对话框:
i. 模态对话框其实是应用程序的一种表达,即“如果您不提供我需要的输入的话那你无法做其它任何事”;
ii. 模态对话框被激活后,对话框的顶层窗口(即它的所属窗口)将一直处于无效状态,除非给对话框提供必要的输入并关闭对话框才行;
iii. 虽然模态对话框会使父窗口处于无效状态,但是仍然可以切换到其它应用程序的窗口,以至于不会因为未给激活模态对话框的程序提供输入而导致其它程序无法正常使用;
iv. 无模式对话框则和其它普通窗口差不多了,在对话框被显示时它的所有者也能被激活;
4) MFC将对话框(模态对话框和非模态对话框)的功能都封装在CDialog类中,这使得对话框的使用变得非常容易;
2. 创建模态对话框的基本步骤:
1) 在资源脚本.rc文件中定义对话框的基本模板(包括对话框中的所有控件,对!这些控件也可以使用脚本语句来定义);
2) 创建一个CDialog对象,并将编译好的对话框资源模板封装在CDialog对象中;
3) 使用CDialog::DoModal函数来创建模态对话框;
!!通常对于一些非常简单的对话框可以直接用CDialog创建对象并使用即可,但是对于一些较复杂的对话框(如果你设计的非常复杂的话)则应该从CDialog类中派生一个你自己的类;
3. 在资源脚本中定义对话框模板:
1) 首先需要确定定义的资源是对话框:
IDD_MYDIALOG DIALOG 0, 0, 160, 68
i. 例子中IDD_MYDIALOG是资源ID,和菜单等资源ID的含义一样,一般约定以IDD作为前缀,即ID Dialog的缩写;
ii. 关键字DIALOG表示定义的资源是对话框;
iii. 0, 0表示对话框显示时的默认位置,该位置是以对话框所属窗口的客户区左上角为原点的,但是位置0, 0比较特殊,并不真正代表客户区的左上角,而是默认将模态对话框放在窗口的中心位置;
iv. 160, 68是对话框的尺寸,即高和宽,这个尺寸当然是用对话框单位表示的;
!!由于字符的高一般是宽的两倍,所以定义对话框时为了使宽高比协调,一般高是宽的两倍左右;
!!一般推荐使用对话框单位,因为使用对话框单位不必考虑屏幕分辨率,但是如果是以像素作为单位就需要考虑屏幕分辨率的,这将非常麻烦;
2) 其次需要确定对话框的样式:
STYLE DS_MODALFRAME WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU
i. STYLE关键字表示接下来定义的是对话框的样式;
ii. 以DS_打头的是对话框特有的风格,即Dialog Style的缩写,以WS_打头的是普通窗口的风格(对话框是一种特殊的窗口);
iii. WS_POPUP作为对话框是一定要有的(对话框都是以弹出的形式显示在用户眼前的;
iv. WS_VISIBLE一般都需要包含,这样就不必手工调用ShowWindow来显示对话框了;
v. WS_CAPTION使对话框具有一个标题,WS_SYSMENU使对话框拥有一个系统菜单;
!关于对话框的特有样式:
DS_MODALFRAME:表示的是一个模板对话框(使用Windows预定义的对话框外观样式),原来对对话框的外观有一定的影响,现在没有了;
DS_CENTER:将对话框放在整个屏幕的中央;
DS_ABSALIGN:把对话框放在整个屏幕的左上角;
DS_CONTEXTHELP:在对话框的标题栏中添加一个问号按钮,以便用户可以获得对话框的上下文帮助信息;
!DS_SYSMODAL:创建一个系统模态对话框,在16位模式下一旦对话框被激活则其它全部窗口(包括其它程序的窗口)都将无效(这表示有严重的系统错误需要处理),但在32位模式下各个应用程序之间被操作系统隔离,因此相对来说是比较安全的,因此在32位模式下,系统模态对话框始终为最顶层窗口,其父窗口(所属的顶层窗口不能激活,和普通的模态对话框一样),但仍然可以激活其它应用程序的窗口(还是和普通模态对话框一样),但是即便激活了其它程序的窗口,但该对话框仍然处于最顶层并挡着其它窗口!!
3) 然后指定对话框的标题文本(前提是必须包含WS_CAPTION样式):
CAPTION "Enter Your Name"
!关键字CAPTION指定后面的字符串将作为对话框的标题;
!但是仍然可以使用CDialog从CWnd继承来的SetWindowText函数手工设定对话框的标题;
4) 接着需要指定对话框的字体:该字体将被应用于对话框的所有控件的文本中
FONT 8, "MS Sans Serif"
i. FONT表示后面指定的是字体;
ii. 8表示字体的大小,即8磅的意思;
iii. 第二个参数就是具体的字体;
!这里MFC默认所有的对话框字体都是MS Sans Serif,因此该语句多余,但是这里是为了展示字体的定义;
!同样可以使用控件从CWnd继承来的SetFont来单独修改某个控件的字体;
5) 最后就是定义对话框中的控件了:
BEGIN
LTEXT "&Name", -1, 8, 14, 24, 8
EDITTEXT IDC_NAME, 34, 12, 118, 12, ES_AUTOSCROLL
DEFPUSBUTTON "OK", IDOK, 60, 34, 40, 14, WS_GROUP
PUSHBUTTON "Cancel", IDCANCEL, 112, 34, 40, 14, WS_GROUP
END
i. 必须将控件的定义都包含在关键字BEGIN和END之间;
ii. 接下来每行定义一个控件;
iii. 每行第一个关键字表示控件的类型(静态控件、编辑空间、列表控件等);
iv. 接下来按照顺序定义控件的各个参数,一般顺序为:控件文本 -> 控件ID -> 控件左上角的位置 -> 控件的尺寸 -> 控件的位置;
!!有些控件可以不具有文本(如上面的编辑控件EDITTEXT,一般初始时里面没有文本,则可以不加该参数)则可以不加文本这一参数;
!!静态控件一般作为其它控件的文本说明而不需要具有消息机制,因此其控件ID没有意义,一般定义为-1即可,可以看到上面的LTEXT就是用来说明后面的编辑控件的,因此其ID就设为-1即可;
!!控件的尺寸和位置都是对话框单位的;
!!所有控件都具有默认样式,可以不显示定义出来,一般都默认包含WS_CHILD(控件必定是子窗口)、WS_VISIBLE(显示窗口的时候必定也同时显示控件)、WS_TABSTOP(可以利用键盘的TAB键再控件之间来回切换输入焦点);
!!如果你比较个性,不想具有一些MFC默认的样式,则可以使用NOT运算符来去掉这些样式,比如NOT WS_TABSTOP来去掉TAB切换焦点的功能;
!!控件文本中的&符号,和定义菜单项文本中的&符号意义相同,只不过它定义的是下一个控件焦点的快捷键,例如上面静态控件文本中的"&Name"将还会使Alt+N称为下一行定义的编辑控件的焦点快捷键(按下Alt+N会把输入焦点切换到编辑控件上);
6) 罗列部分脚本中可以定义的控件以及其默认的样式:按照控件名关键字、控件类型、默认样式的方式排列
LTEXT,左对齐静态文本,SS_LEFT|WS_GROUP
RTEXT,右对齐静态文本,SS_RIGHT|WS_GROUP
CTEXT,居中对齐静态文本,SS_CENTER|WS_GROUP
PUSHBUTTON,普通下压按钮,BS_PUSHBUTTON|WS_TABSTOP
DEFPUSHBUTTON,默认下压按钮(可以使用空格来表示按钮按下),BS_DEFPUSHBUTTON|WS_TABSTOP
EDITTEXT,编辑控件,ES_LEFT|WS_BORDER|WS_TABSTOP(可以见得编辑控件是左对齐的)
CHECKBOX,复选框,BS_CHECKBOX|WS_TABSTOP
AUTOCHECKBOX,自动复选框,BS_AUTOCHECKBOX|WS_TABSTOP
...
!!可以见得控件的定义实际上是通过控件样式来决定控件的类型的;
!!!所以,也可以通过一般的CONTROL来定义任意控件;
7) 通过关键字CONTROL来定义任意控件:
CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON|WS_TABSTOP|WS_GROUP, 60, 34, 40, 14
i. CONTROL关键字表示接下来定义的是一个一般类型的控件;
ii. 各参数的约定的顺序是:控件文本 -> 控件ID -> 控件窗口注册时的类名,即WNDCLASS名字 -> 控件的样式 -> 位置 -> 尺寸
iii. 对于WNDCLASS名字,BUTTON代表下压按钮、单选框、复选框和组框,EDIT代表编辑控件等;
iv. CONTROL一般用于自定义的控件,而此时WNDCLASS类名则为自己设计的类的类名(用RegisterClass注册过的);
v. 这种方式定义控件相对来说较为原始,样式里只有WS_CHILD和WS_VISIBLE是默认的,可以不显示写出来,其余的包括WS_TABSTOP在内的样式都需要显式添加;
!!!CONTROL定义法最常用于定义高级通用控件,例如进度条、微调按钮等,都必须使用CONTROL来定义!
4. 对话框的键盘接口总结:
1) 总共有4个因素会影响对话框的键盘接口,后面将一一罗列;
2) 控件定义的顺序:
i. 控件在模板中定义的顺序主要影响了Tab键和Shfit-Tab键切换控件输入焦点时的顺序;
ii. 要使用Tab和Shift-Tab切换焦点,控件必须包含WS_TABSTOP样式;
iii. Tab切换焦点的顺序就是控件在模板中定义的顺序;
3) 控件正文使用“&”来指定快捷键:
i. 可以通过Alt+(*)的方式将焦点自动移到指定的控件上;
ii. 如果焦点已经停留在相同类型的控件上的话,则直接按&修饰的字母键即可将焦点移到指定的控件上了,比如,一个PUSHBUTTON的正文定义为"&OK",另一个为"&Cancel",还有一个为"Haha",如果此时焦点已经停在了Cancel或者Haha上,则只需要按下O键就能将焦点移到OK按钮上了,而不需要Alt+O来移动焦点;
!前提是焦点停留在相同类型的控件上才行,诸如上例三个控件都是下压按钮;
!如果一个控件没有正文文本(例如上例的编辑框),则为了给这样的控件加快捷键,则可以在其前面定义一个静态文本控件,并给该文本添加快捷键标记&;
4) 使用WS_GROUP样式来集成控件:
i. 用WS_GROUP集成的一组控件之间可以用上下左右箭头来相互切换焦点;
ii. 对于WS_GOURP集成之外的各个控件组之间只能用Tab键来相互切换焦点而不能用箭头来切换焦点;
iii. WS_GROUP专门用于给复选框和单选框分组,但是在对话框中也常将一个单独的按钮分为一组,这样就可以禁止在各单独按钮之间用方向键来切换焦点而只能使用Tab键来切换焦点,这样使逻辑上更加清晰;
5) 默认按钮:
i. 即用DEFPUSHBUTTON或用BS_DEFPUSHBUTTON定义的按钮;
ii. 这些按钮在对话框刚显示时就会在设定为默认按钮的外围加一层虚线,按下Enter键可以模拟鼠标点击该按钮;
iii. 当然也可以用Tab键、方向键等在若干个按钮之间切换默认按钮,视觉上表现为虚线框随着Tab和方向键移动到其它按钮上,这样默认按钮也会随之改变;