在基于对话框的应用程序中,下压按钮是最常见的控件之一,如图6.10所示。
图6. 10 下压按钮
下面的步骤讲述如何向对话框中添加下压按钮控件。
1. 在ResourceView中双击需要添加下压按按钮控件的对话框模板,Developer Studio将在资源编辑器中打开该对话框模板。如图6.11所示。
2. 在图6.3所示的控件工具窗口中选择图标,直接使用鼠标在对话框中绘制出一个下压按钮。
3. 右击所绘制的下压按钮,选择Properties命令打开其属性对话框,设置下压按钮的各项属性。下面详细描述这些属性的含义:
图6. 11 在资源编辑器中打开一对话框模板
图6. 12 在对话框中绘制下压按钮控件
一般属性:
ID: |
在头文件中定义的符号。类型:符号、整数或用引号括起来的字符串 |
Caption: |
控件标签文本。如果在标题中的某个字母前加上了“&”符号,该字母在显示时将被加上下划线,相应的“&”符不会被显示。在运行直接按下加有下划线的字母同单击按钮具有同样的效果。默认情况下,资源编辑器对按钮标题的命名依赖于控件的类型,如Button1、Button2等。 |
Visible: |
决定当应用程序第一次运行时控件是否可见。类型:布尔值 默认值为真 |
Disabled: |
决定当对话框创建时该控件是否显示为禁止状态。类型:布尔值 默认值为假 |
Group: |
指定一组控件中的第一个控件。在同组控件中用户可以使用箭头键在控件之间移动。以tab order为序,在该控件之后的所有该属性值为False的控件将被视为同一组控件,直到遇上Group属性标记为True的控件为止。类型:布尔值 默认值为假 |
Tabstop: |
决定用户是否可以使用TAB键来定位到该控件。类型:布尔值 默认值为假 |
HelpID: |
为控件指定一个帮助标识符。该标识符基于相应的资源标识符。类型:布尔值 默认值为假 |
样式:
Default button: |
该属性为真时,控件将作为对话框中的默认按钮,默认按钮在对话框第一次显示时具有粗的黑边,用户在对话框中按下ENTER键相当于单击该按钮。一个对话框中只允许有一个默认按钮。类型:布尔值 默认值为假 |
Owner draw: |
创建一个自绘按钮。使用自绘按钮可以定制按钮的外观。使用自绘按钮需要重载下面的两个函数或其中之一:CWnd::OnDrawItem和CButton::OnDraw。 |
Icon: |
在按钮显示时使用一个图标来代替文本。类型:布尔值 默认值为假 该按钮样式为Windows 95中新引入的按钮样式 |
Bitmap: |
在按钮显示时使用位图来代替文本。类型:布尔值 默认值为假 该样式为Windows 95中新引入的样式 |
Multi-line: |
当按钮文本太长时使用多行回绕的方式进行显示。类型:布尔值 默认值为假 |
Notify: |
按钮控件被单击或双击时通知父窗口。类型:布尔值 默认值为真 |
Flat: |
使用平面外观代替按钮默认的三维外观。类型:布尔值 默认值为假 |
Horizontal alignment: |
设置按钮标题文本的对齐方式(左对齐、右对齐、居中对齐或使用默认位置) |
Vertical alignment: |
设置按钮标题文本的对齐方式(向上对齐、向下对齐、居中对齐或使用默认位置) |
扩展样式
Client edge: |
使按钮看起来有下凹的感觉。类型:布尔值 默认值为假 |
Static edge: |
在按钮边缘创建边框。类型:布尔值 默认值为假 |
Modal frame: |
提供一个三维框架 |
Transparent: |
使控件透明。位于透明窗口下面的窗口不会被该窗口所覆盖。具有透明样式的窗口仅当所有底层兄弟窗口完成更新之后才会收到WM_PAINT消息。类型:布尔值 默认什为假 |
Accept files: |
是否接受文件拖放。如果在控件上放下文件时,控件将接收到WM_DROPFILES消息。类型:布尔值 默认值为假 |
No parent notify: |
指定子窗口不向父窗口发送WM_PARENTNOTIFY消息。类型:布尔值 默认值为假 |
Right aligned text: |
指定文本为右对齐。类型:布尔值 默认值为假 |
Right-to-left reading order: |
使用从右向左的阅读方式来显示文本。主要用于希伯来语系和阿拉伯语等。类型:布尔值 默认值为假 |
- 技巧:
- 如果需要在控件的标题文本中使用“&”符,可以使用双写的“&”符,如按钮文本“&File && Directory”在显示时将成为。
- 如果需要在控件标题中使用多行文本,可以将按钮控件的Multiline属性设置为真,然后在需要换行的地方使用转义字符 "\n" 或 "\r"。在Multiline属性值为真的情况下,如果文本行的宽度超过了控件的宽度,即使没有使用换行转义字符,文本也将会在合适的地方进行折行处理。但要注意,其它一些转义字符序列,如 "\t" 等不被控件所支持。
我们一般只处理按钮控件一种通知消息:BN_CLICKED,该消息表示用户单击了该按钮控件。按钮控件的另外一种通知消息是BN_DOUBLECLICKED,它表示用户双击了按钮控件,但是一般情况下我们不需要处理下压按钮的双击事件。
图6. 13 ClassWizard对话框:Message Maps选项卡
下面我们介绍如何为下压按钮的单击事件添加消息处理函数和消息映射,这里我们假设所添加的下压按钮ID为IDC_CLICKHERE,标题文本为“单击这里(&C)”,其余属性使用默认设置。
第一种方法如下:
1. 在资源编辑器右击按钮IDC_CLICKHERE,选择“ClassWizard”,打开如图6.13所示的窗口,单击Message Maps选项卡。
确信在Project处选择的工程为当前工程,Class name处为当前对话框模板所对应的类。Object IDs列表框中给出了当前对话框类中的所有对象标识符,从中选择IDC_CLICKHERE,即我们刚才添加的下压按钮,这里,在右边的Message列表框中给出了当前对象的消息,这里即BN_CLICKED和BN_DOUBLECLICKED,从中选择BN_CLICKED (它代表了按钮的单击事件),然后单击右边的Add Function按钮(注意:Add Function按钮仅当已选择了某一消息时才会出现)。
图6. 14 决定是否需要更改命令处理函数名
图6. 15 为控件通知消息添加处理函数
2. 在随后出现的对话框(如图6.14所示)中选择是否需要更改命令处理函数的函数名。ClassWizard的默认函数名遵从于下面的命令协议:
前缀On + 控件ID中除去IDC_前缀的剩余部分
这里我们接受默认的命令处理函数名OnClickhere。
3. 新添加的命令处理函数OnClickhere已经出现在图6.13所示的对话框中的下面的Member functions部分。同时,Edit Code按钮获得输入焦点。单击该按钮,ClassWizard将在Developer Studio的代码编辑器窗口中打开函数OnClickhere,并高亮度显示下面的// TODO注释:
// TODO: Add your control notification handler code here
我们使用下面的代码来替换上面的// TODO注释:
MessageBox
("您刚才单击了按钮 IDC_CLICKHERE, 因此相应的命令处理函数 OnClickhere 被调用!");
第二种方法:
1. 在资源编辑器中右击按钮IDC_CLICKHERE,选择Events命令,打开如图6.15所示的对话框:
2. 在Class or object to handle列表框中选择IDC_CLICKHERE,然后在New Windows messages/events列表框中选择BN_CLICKED,单击右边的Add and Edit,余下的步骤同第一种方法的第2步开始相同。
这时编译并运行上面的程序,单击标签为“单击这里”的下压按钮,弹出如图所示的消息框。
图6. 16 程序PushButton的运行结果
下面我们来看相应的消息映射。
首先,在类CPushButtonDlg的定义中添加了消息处理函数OnClickhere的原型:
afx_msg void OnClickhere();
函数OnClickhere的声明被放进了两行注释分隔符//{{AFX_MSG(CPushButtonDlg)和//}}AFX_MSG之间。前面我们提到过,ClassWizard将由它定义的消息处理函数的声明放入这两行注释分隔符之间。
下面我们来看相应的消息映射入口。它位于实现文件PushButtonDlg.cpp中的两个宏BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间:
ON_BN_CLICKED(IDC_CLICKHERE, OnClickhere)
其中第一个参数IDC_CLICKHERE为控件的标识符,第二个参数OnClickhere为相应的消息处理函数。
一旦弄清楚了由ClassWizard添加这些代码,我们就可以手动的添加命令消息处理函数的消息映射。但是,从上面的过程中我们可以很明显的看出一点,使用ClassWizard来完成这一点要简单得多。
下面我们介绍与下压按钮控件有关的几个技巧:
(1) 在运行过程中改变下压按钮的标题文本
有时候我们需要在程序运行的过程中改变按钮的标题文本。典型的,我们可能需要根据用户所输入的数据来决定按钮上应该写些什么。我们到前面去看一下表6.14,看一看有什么成员函数可以完成这种功能。
很好,类CWnd的成员函数SetDlgItemText可以由窗口或对话框所有的控件的标题文本。其原型如下:
void SetDlgItemText( int nID, LPCTSTR lpszString );
其中nID为控件标识符(ID),lpszString为控件的新标题文本。
成员函数SetDlgItemText事实上是向控件发送一条WM_SETTEXT消息,该消息的wParam参数必须为0,而lParam为指向窗口标题文本字符串的指针。
因此,SetDlgItemText等价于下面的函数调用:
CWnd::SendDlgItemMessage(nID, WM_SETTEXT, 0, LPARAM(lpszString));
或
::SendDlgItemMessage(GetSafeHwnd(), nID, WM_SETTEXT, 0,LPARAM(lpszString));
比如说,我们用以将下面的代码添加到OnClickhere中对MessageBox的调用之后:
SetDlgItemText(IDC_CLICKHERE,"此按钮已被单击过.");
(2) 使用按钮无效(或有效)
假设我们在上面的例子中希望用户只能单击按钮IDC_CLICKHERE一次。那么,按钮IDC_CLICKHERE被单击一次之后应该变灰,以禁止用户再次单它。这可以通过下面的步骤来实现:
首先调用对话框对象的成员函数GetDlgItem (该成员函数在类CWnd中定义),该成员函数获得一个指向对话框中的控件的CWnd指针,然后再通过该指针调用控件对象的成员函数EnableWindow (该成员函数在类CWnd中定义)。该成员函数允许或禁止调用它的CWnd对象对应窗口。整个过程可以使用一行语句来实现,如下所示:
GetDlgItem(IDC_CLICKHERE)->EnableWindow(FALSE);
其中GetDlgItem函数以控件的ID为参数,返回值的类型为CWnd *,如果需要通过该指针调用在类CButton所定义的成员函数,可以使用强制类型转换。EnableWindow以一个布尔值为参数,该参数为真时表示允许该窗口接受鼠标和键盘输入,为假时禁止该窗口接受鼠标和键签署输入。这里再一次强调,控件本身也是一种窗口。
将上面的代码放到命令处理函数OnClickhere的最后,这样,在单击一次按钮“单击这里”之后,对话框如图6.17所示。
图6. 17 处于禁止状态的控钮控件
此外,如果使用了ClassWizard为按钮建立了对话框的成员变量的数据映射,则可以通过对话框中的成员变量直接操纵控件。在本例中,如果我们已将下压按钮映射为类型为CButton的成员变量m_bnClickhere,则可以通过下面成员函数调用设置按钮的允许状态:
m_bnClickhere->EnableWindow(FALSE);
(3) 使按钮获得输入焦点
具有输入焦点的窗口将会得到所有的键盘输入消息。我们可以通过类CWnd的成员函数GetFocus来使对话框中的控件获得输入焦点。
试将下面的代码加到消息处理函数OnInitDialog的return语句前:
m_bnClickhere.SetFocus();
或
GetDlgItem(IDC_CLICKHERE)->SetFocus();
编译并运行程序。非常奇怪,输入焦点并没有被设置到下压按钮“单击这里”上。依然是按钮“确定”拥有当前输入焦点。
请注意这样的事实:
- 注意:
- 如果在消息处理成员函数OnInitDialog中将输入焦点设置到指定的控件,则函数应该返回FALSE,这是因为如果WM_INITDIALOG消息的处理函数返回真值,Windows会将输入焦点设置为对话框中的第一个控件。因此,如果在该处理函数中设置了控件的输入焦点,WM_INITDIALOG消息的处理函数应该返回假值。
将下面的代码
return TRUE;
修改为
return FALSE;
这时再编译并运行程序,则输入焦点将被正常地设置到下压按钮“单击这里”上。这时按下空格键相当于在按钮“单击这里”上单击鼠标左键。
(4) 使用图形代替文本
在一些应用程序,尤其是一些多媒体应用程序中,我们希望按钮的外观看起来更加的美观,比如说我们希望使用多变的图形代替单调乏味的纯文本。对于一般的按钮控件,我们可以使用两种方法来在按钮中使用图形来代替文本。
第一种方法是使用图标来代替文本。下面的示例说明了这种用法:
1. 使用资源编辑器或其它工作编辑一个图标资源,其ID为IDI_CLICKHERE,图案如图6.18所示。
2. 在希望使用图标图案的按钮控件的Properties属性框在Styles选项卡中设置Icon属性为真。并按图6.19修改对话框及其中控件的大小。
3. 在类CPushButtonDlg的消息处理成员函数OnInitDialog中添加下面的代码。这些代码应该在对基类的OnInitDialog成员函数的调用之后。
图6. 18 图标IDI_CLICKHERE
图6. 19 为使用图标按钮修改
对话框中控件的大小
HICON hIcon=AfxGetApp()->LoadIcon(IDI_CLICKHERE);
m_bnClickhere.SetIcon(hIcon);
编译该应用程序,运行结果如图6.20所示。
图6. 20 在按钮中使用图标的示例
这时单击按钮Click Here,图标图案会有向右和向下下压的效果。
第二种方法是使用位图来代替文本。步骤如下:
图6. 21 位图资源IDB_CLICKHERE
1. 向工程资源中添加如图6.21的位图资源,其ID为IDB_CLICKHERE。
2. 在希望使用位图图案的按钮控件的Properties属性框在Styles选项卡中设置Bitmap属性为真。我们注意到Icon属性和Bitmap属性是互斥的,即选择一属性的同时也清除了另一属性。并按图6.19修改对话框及其中控件的大小。同时参考最终运行结果(如图6.22)修改对话框及其按钮的大小。
3. 在OnInitDialog成员函数中添加如下的代码:
HBITMAPhBitmap=LoadBitmap(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDB_CLICKHERE));
m_bnClickhere.SetBitmap(hBitmap);
在上面的代码中,我们使用Win32 API函数LoadBitmap (注意它不是类CWinApp的成员函数)来加载位图资源IDB_CLICKHERE,从而获得位图句柄hBitmap,最后以该句柄为参数调用类CButton的成员函数SetBitmap。
编译并运行上面的程序,得到如图6.22所示的运行结果。
图6. 22 在按钮中使用位图的示例
- 注意:
- 在上面的示例程序中我们使用了真彩色(24位)的位图。这样的位图不可以使用资源编辑器来进行编辑。上面的位图是使用其它专门的图形工具来进行编辑并保存到文件Clickhere.bmp中的。请按下面的步骤将该文件添加为工程的资源:
1. 选择Insert菜单下的Resource命令,打开如图所示的对话框。
图6. 23 插入新的资源
2. 从中单击Import按钮,从位图文件Clickhere.bmp中输入资源。注意在文件类型中选择“All files (*.*)”。
Developer Studio将弹出如图6.24所示的警告对话框。该对话框表明位图资源已被正确添加。但由于使用了多于256色的颜色数,因此该资源不可以在资源编辑器中打开。
图6. 24 试图添加使用了多于256色的位图资源时的警告消息框
3. 按正常的方法将所添加的位图资源的ID修改为IDB_CLICKHERE。必要时重新编辑资源文件或工程。