友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
C语言实例教程(PDF格式)-第17部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
生的类都可以提供了一个消息映射来处理消息,这时我们需要在类声
明中使用宏DECLARE_MESSAGE_MAP,然后在定义该类的成员函数
的。CPP文件中使用宏BEGIN_MESSAGE_MAP,然后为每一个消息处理函
数添加宏入口,最后使用宏END_MESSAGE_MAP。
l 注意:
l 如果你在DECLARE_MESSAGE_MAP之后声明了任何成员,必须为它们
重新指定新的访问类型(public、private或protected)。为了避
免出现错误,我们一般都在类声明的最底部使用宏
DECLARE_MESSAGE_MAP。
…………………………………………………………Page 185……………………………………………………………
第四节 对话框类
本节讲述应用程序DialogDemo的对话框类CDialogDemoDlg。由于
DialogDemo是一个基于对话框的应用程序,因此该对话框也将是应用
程序的主窗口。
下面我们先给出头文件DialogDemoDlg。h的清单:
// DialogDemoDlg。h : 头文件
//
#if !defined
(AFX_DIALOGDEMODLG_H__7ABABF8A_0C8C_11D2_BC21_0000B4810A31__INCLUDED_)
#define AFX_DIALOGDEMODLG_H__7ABABF8A_0C8C_11D2_BC21_0000B4810A31__INCLUDED_
#if _MSC_VER 》= 1000
#pragma once
#endif // _MSC_VER 》= 1000
/////////////////////////////////////////////////////////////////////////////
// CDialogDemoDlg 对话框
class CDialogDemoDlg : public CDialog
{
// 构造
public:
CDialogDemoDlg(CWnd* pParent = NULL); // 标准构造函数
// Dialog Data
//{{AFX_DATA(CDialogDemoDlg)
enum { IDD = IDD_DIALOGDEMO_DIALOG };
// 注意:ClassWizard 将在此添加数据成员
//}}AFX_DATA
// 由 ClassWizard 生成的虚函数重载
//{{AFX_VIRTUAL(CDialogDemoDlg)
…………………………………………………………Page 186……………………………………………………………
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
//}}AFX_VIRTUAL
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
//{{AFX_MSG(CDialogDemoDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysmand(UINT nID; LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio 将在紧贴前一行前面添加附加的声明
#endif
// !defined(AFX_DIALOGDEMODLG_H__7ABABF8A_0C8C_11D2_BC21_0000B4810A31__INCLUDED_)
ClassWizard和AppWizard在生成代码时向源代码文件中插入了一些特
定的格式化注释分隔符,以标明那些ClassWizard可以写入的地方。
在前几节的内容中我们已经看到了一些这样的注释分隔符,如
AFX_MSG和AFX_MSG_MAP等。在头文件DialogDemoDlg中出现了一些新
的分隔符,如AFX_DATA用来标记在头文件中为对话框数据交换
(dialog data exchange,DDX)所声明的成员变量的开始和结束。
AFX_VIRTUAL用来标记在头文件中由ClassWizard生成和管理的虚函数
的开始和结果。在。CPP文件中没有对应的块。
下一个看到的函数是DoDataExchange。框架调用该函数来交换和验证
…………………………………………………………Page 187……………………………………………………………
对话框数据。该函数从来不直接调用,而总是在成员函数UpdateData
中调用。成员函数UpdateData用户初始化对话框控件或从对话框中获
取数据。
如果需要利用框架的自动数据交换和验证,则需要在从类CDialog派
生应用程序特定的对话框时得载该成员函数。ClassWizard会为你创
建一个该成员函数的重载版本,在该重载版本的DoDataExchange函数
中包括了所期望的对话框数据交换 (DDX)和有效性验证 (DDV)的全局函
数的 “数据映射”。
DoDataExchange函数的重载版本将在后面的内容中给出和进行更为详
细的分析。
成员变量m_hIcon包括了应用程序主对话框的图标句柄。
下面介绍重载的几个消息映射函数。
第一个介绍的是OnInitDialog成员函数。该成员函数为消息
WM_INITDIALOG的处理函数。当成员函数Create、CreateIndirect或
DoModal被调用时该消息被发送至对话框,但此时对话框尚未显示于
屏幕上。
一般情况下我们重载该成员函数以进行一些对话框的初始化。在
OnInitDialog成员函数的重载版本中,我们应该先调用基类的
OnInitDialog成员函数,但无需理会其返回值。在正常情况下,
OnInitDialog成员函数的重载版本返回TRUE。
不需要为该成员函数添加一个消息映射入口。这是因为Windows通过
一个标准全局对话框函数来调用OnInitDialog函数,该对话框函数对
所有的MFC对话框都是一样的,这种调用并不通过消息映射来完成。
表4。3 OnSysmand成员函数的nID参数
参数nID的值 含义
SC_CLOSE 关闭CWnd对象
SC_HOTKEY 激活与应用程序指定的热键相关联的CWnd
对象。lParam参数的低位字节标识了待激
活窗口的HWND。
SC_HSCROLL 垂直滚动
SC_KEYMENU 通过按键检索菜单
…………………………………………………………Page 188……………………………………………………………
SC_MAXIMIZA 最大化CWnd对象
(或SC_ZOOM)
SC_MINIMIZE 最小化CWnd对象
(或SC_ICON)
SC_MOUSEMENU 通过鼠标单击检索菜单
SC_MOVE 移动CWnd对象
SC_NEXTWINDOW 移到下一窗口
SC_PREVWINDOW 移到上一窗口
SC_RESTORE 恢复窗口到通常位置和大小
SC_SCREENSAVE 执行由SYSTEM。INI文件的'boot'段指定的
屏幕保护程序
SC_SIZE 改变窗口的大小
SC_TASKLIST 运行或激活Windows任务管理程序
(Windows Task Manager)
l 注意:
l OnInitDialog成员函数的返回值将影响应用程序设置对话框中控
件的输入焦点的方式。如果OnInitDialog返回非零值,窗口设置
输入焦点为对话框中的第一个控件。如果已显式的将输入焦点设
置为对话框中的某个控件,那么应该返回0。
接下来声明的是成员函数OnSysmand,它是WM_SYSMAND消息的
处理函数。当用户从控制菜单选择了某一个命令或单击了最大化或最
小化按钮。
该函数的原型如下:
afx_msg void OnSysmand( UINT nID; LPARAM lParam );
第一个参数nID指定了系统命令要求的类型,它可以为表4。3所示值之
一。如果通过鼠标选择控制菜单命令,则参数lParam包含了鼠标的当
前坐标。低位字代表x坐标,而高位字代表y坐标。
在默认情况下,OnSysmand执行表4。3所示的预定义行为。
…………………………………………………………Page 189……………………………………………………………
在WM_SYSMAND消息中,参数nID的低4位由Windows内部使用,当应
用程序测试nID的值时,必须使用按位与(bitwise…AND)操作符组合值
0xFFF0和nID来得到正确的结果。
应用程序可以在任何时候通过传递一个WM_SYSMAND消息给成员函
数OnSysmand来执行任何系统命令。
已被定义为用来选择控制菜单项的加速键 (快捷键)消息将解释为
OnSysmand的调用,其它快捷键将翻译为WM_MAND消息。
l 注意:
l 控制菜单项可以通过成员函数GetSystemMenu、AppendMenu、
InsertMenu以及ModifyMenu来进行修改。修改了控制菜单的应用
程序必须处理WM_SYSMAND消息,所有未被应用程序处理的消息
必须传递给成员函数OnSysmand。由应用程序添加的命令值必
须由应用程序处理,而不能传递给函数OnSysmand。
l 该成员函数由框架所调用,以允许应用程序处理Windows消息。传
递给函数的消息代表了当获得消息时由框架获得的参数。如果你
调用了基类的实现,该实现将使用消息最初传递的参数,而不是
由函数提供的参数。
成员函数OnPaint是消息WM_PAINT的处理函数,它当窗口客户区需要
重绘时被调用。
成员函数OnQueryDragIcon对应于消息WM_QUERYDRAGICON,它也是由
框架在最小化窗口而没有为类定义一个图标时调用。系统通过对该函
数的调用来获得当用户拖动被最小化的窗口时用来显示的光标。
如果应用程序返回了一个图标名光标的句柄,系统将其转换了黑白
的。该句柄必须标识一个与显示驱动程序分辨率相兼容的单色光标或
图标。应用程序可以调用CWinApp::LoadCursor或CWinApp::LoadIcon
成员函数来从它的可执行文件中的资源内加载一个光标或图标并获得
其句柄。
下面给出类CDialogDemoDlg的实现文件DialogDemoDlg。cpp的清单:
// DialogDemoDlg。cpp : 实现文件
//
#include 〃stdafx。h〃
…………………………………………………………Page 190……………………………………………………………
#include 〃DialogDemo。h〃
#include 〃DialogDemoDlg。h〃
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE'' = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg 用于 App About 的对话框
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// 由 ClassWizard 生成的虚函数重载
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
//}}AFX_VIRTUAL
// 实现
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
…………………………………………………………Page 191……………………………………………………………
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg; CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// 没有消息处理函数
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDialogDemoDlg 对话框
CDialogDemoDlg::CDialogDemoDlg(CWnd* pParent /*=NULL*/)
: CDialog(CDialogDemoDlg::IDD; pParent)
{
//{{AFX_DATA_INIT(CDialogDemoDlg)
// 注意:ClassWizard 将在此添加成员初始化
//}}AFX_DATA_INIT
…………………………………………………………Page 192……………………………………………………………
// 注意在 Win32 中 LoadIcon 不需要一个相应的 DestroyIcon
m_hIcon = AfxGetApp()…》LoadIcon(IDR_MAINFRAME);
}
void CDialogDemoDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDialogDemoDlg)
// 注意:ClassWizard 将在此添加 DDX 和 DDV 调用
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDialogDemoDlg; CDialog)
//{{AFX_MSG_MAP(CDialogDemoDlg)
ON_WM_SYSMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDialogDemoDlg 消息处理函数
BOOL CDialogDemoDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 添加 〃About。。。〃 菜单项到系统菜单
// IDM_ABOUTBOX 必须在系统命令范围之内
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX 《 0xF000);
…………………………………………………………Page 193……………………………………………………………
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu。LoadString(IDS_ABOUTBOX);
if (!strAboutMenu。IsEmpty())
{
pSysMenu…》AppendMenu(MF_SEPARATOR);
pSysMenu…》AppendMenu(MF_STRING; IDM_ABOUTBOX; strAboutMenu);
}
}
// 该当前对话框设置图标。当应用程序主窗口不为对话框时由框架自动完成该任务
SetIcon(m_hIcon; TRUE); // 设置大图标
SetIcon(m_hIcon; FALSE); // 设置小图标
// TODO: 在此添加额外初始化
return TRUE; // 除非将焦点设置为某一控件,否则返回 TRUE
}
void CDialogDemoDlg::OnSysmand(UINT nID; LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout。DoModal();
}
else
{
…………………………………………………………Page 194……………………………………………………………
CDialog::OnSysmand(nID; lParam);
}
}
// 如果你向对话框添加了一个最小化按钮,你将需要下面的代码来绘制图标。
// 对于使用文件/视模型的 MFC 应用程序,这一步由框架自动完成。
void CDialogDemoDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 重绘设备上下文
SendMessage(WM_ICONERASEBKGND; (WPARAM) dc。GetSafeHdc(); 0);
// 在窗户区矩形中居中图标
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect。Width() cxIcon + 1) / 2;
int y = (rect。Height() cyIcon + 1) / 2;
// 绘制图标
dc。DrawIcon(x; y; m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
…………………………………………………………Page 195……………………………………………………………
// 在用户拖动被最小化的窗口时系统调用该函数来获得用于显示的光标。
HCURSOR CDialogDemoDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
在实现文件DialogDemoDlg。cpp 中包括了类CAboutDlg的定义,该类封
装了应用程序的 “关于”对话框。由于类CAboutDlg与类
CDialogDemoDlg相比要简单得多,所以我们在此不再讲述。下面我们
主要分几个部分来讲述类CDialogDemoDlg 。
(1) 构造函数
在类CDialogDemoDlg的构造函数中,注释分隔符AFX_DATA_INIT用于
在对话框类的构造函数中标记对话框数据交换 (DDX)成员变量初始化
的开始和结束。接着使用MFC全局函数AfxGetApp获得指向应用程序对
象的指针,再通过该指针调用成员函数LoadIcon加载图标,并将其句
柄放入成员变量m_hIcon。
类CDialogDemoDlg的成员函数DoDataExchange只是简单的调用基类的
对应成员函数。在成员函数DoDataExchange 内,注释分隔符
AFX_DATA_MAP用于标记对话框数据交换函数调用的开始和结束。
l 注意:
l 尽管在接下来的一章中,我们将要再次对菜单的应用作系统的介
绍,但考虑到程序说明的完整性,在这里,我们仍然先对其作简
明的介绍。
(2) 消息处理成员函数OnInitDialog
消息处理函数OnInitDialog首先调用基类的对应成员函数。接着的两
个ASSERT宏断言IDM_ABOUTBOX处于系统命令范围内。ASSERT宏以一个
布尔表达式为参数,然后对该表达式求值,如果结果为0 (假),
ASSERT输出一个诊断信息,然后中断程序,如果结果为非0,宏
ASSERT什么也不做。
由宏ASSERT输入的诊断信息具下面的格式:
…………………………………………………………Page 196……………………………………………………………
assertion failed in file in line
在这里文件名代表了出现ASSERT错的源代码文件,行号指出了源代码
文件中出错的行。
在MFC的发行版本 (Release version)中,宏ASSERT并不对表达式进行
求值,从而也不会中断程序的执行。与宏ASSERT不同,宏VERIFY在
MFC中调试版本和发行版本中都将对表达式进行求值。
接下来,由类CWnd的成员函数GetSystemMenu返回控制菜单的一个拷
贝。如果传递给该函数的参数为假,函数GetSystemMenu返回正在使
用的控制菜单的一个拷贝的句柄。该拷贝同控制菜单完全相同,但它
可以修改。如果传递的参数为真,函数GetSystemMenu重置控制菜单
为默认值,如果原有控制菜单经过修改,该改动将丢失。在这种情况
下,函数GetSystemMenu的返回值是未定义的。可以通过由成员函数
GetSystemMenu返回的指针使用CMenu::AppendMenu、
CMenu::InsertMenu或CMenu::ModifyMenu函数来改变控制菜单。
控制菜单最初包括由不同ID值,如SC_CLOSE、SC_MOVE和SC_SIZE等标
识的项。这些控制菜单中的项产生WM_SYSMAND消息。所有预定义
的控制菜单具有大于0xF000的ID值,因此,如果应用程序向控制菜单
中添加了新的项,这些项所使用的ID值应该小于0xF000。
Windows可以自动的决定是否使标准控制菜单中的项变灰。类CWnd可
以通过响应WM_INITMENU来执行检查或变灰,该消息在所有菜单显示
之前发送。
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!