注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

jasonyang9的博客

随便写写

 
 
 

日志

 
 

(怀旧系列)VC程序设计(孙鑫老师)听课笔记:08 对话框 2  

2013-01-20 16:59:57|  分类: programming |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
(怀旧系列)VC程序设计(孙鑫老师)听课笔记:08 对话框 2 - jasonyang9 - jasonyang9的博客
 

======
对话框
======

基于对话框的应用程序比较简单,有一个CAboutDlg类(从CDialog派生),是一个关于对话框;CXXXApp类(从CWndApp派生),其对象代表应用程序本身;CXXXDlg类(从CDialog派生),是一个对话框。

设计一个会“逃跑”的按钮(即鼠标点不到):

// 新建一个基于对话框的应用程序
// 用资源编辑器增加一个按钮,Caption改为“你能抓住我吗?”,然后复制一个,设想当用户将鼠标移动到一个按钮上时,隐藏该按钮,并显示另外一个按钮,造成“逃跑”的假象
// 捕获鼠标需要按钮自己来完成(当按钮收到鼠标移动消息时,就表示用户将鼠标移动到了该按钮上方),从CButton派生一个CWeiXinBtn(用ClassWizard操作,Add Class,基类是CButton)
// 将2个按钮控件关联CWeiXinBtn的控件变量(用ClassWizard操作,Add Variable...,Category为Control,Variable type为CWeiXinBtn),注意需要在CXXXDlg中包含CWeiXinBtn的头文件
// 用Class View对CWeiXinBtn增加WM_MOUSEMOVE消息处理函数OnMouseMove
// 要让CWeiXinBtn对象隐藏自己可调用ShowWindow(SW_HIDE)实现;但要显示对方,则需在CWeiXinBtn中定义一个CWeiXinBtn的指针,指向对方,并调用ShowWindow(SW_SHOW),用Class View操作
// 在WeiXinBtn.h中会增加:

CWeiXinBtn* m_pBtn;

// 让2个CWeiXinBtn对象中的m_pBtn指向对方,假设:

CWeiXinBtn m_btn1; // 首地址:0088:4400
CWeiXinBtn m_btn2; // 首地址:0088:4660
让 m_btn1.pWeiXinBtn = 0088:4660,即指向m_btn2的首地址
让 m_btn2.pWeiXinBtn = 0088:4400,即指向m_btn1的首地址

// 在OnInitDialog中进行赋值:

BOOL CXXXDlg::OnInitDialog()
{
...
m_btn1.pWeiXinBtn = &m_btn2; // 用&取地址符获取类对象的首地址
m_btn2.pWeiXinBtn = &m_btn1;
...
}

// 在CWeiXinBtn类中增加WM_MOUSEMOVE消息处理函数OnMouseMove
void CWeiXinBtn::OnMouseMove(UINT nflags, CPoint point)
{
ShowWindow(SW_HIDE); // 隐藏自己
m_pBtn->ShowWindow(SW_SHOW); // 显示对方

CButton::OnMouseMove(nflags, point);
}

// 为了初始化隐藏一个按钮,去掉一个按钮的Visible选项(用资源编辑器操作)

// 也可由SetWindowPos(设置窗口位置)来改变按钮显示位置,实现“逃跑”按钮效果(随机位置)


属性表单、属性页(标签)的编程:

// 用资源编辑器插入3个属性页(IDD_PROPPAGE_LARGE等),修改它们的ID号(IDD_PROP1、IDD_PROP2、IDDPROP3)和Caption(Page1、Page2、Page3)
// 这些插入的属性页资源的Style是Child,Border是Thin,System menu没有复选,Disabled被复选,这些和一般的对话框不同
// 在IDD_PROP1中插入1个组框(“请选择你的职业:”),3个单选按钮(“程序员”、“系统工程师”、“项目经理”),1个静态文本(“请选择你的工作地点),1个列表框
// 在IDD_PROP2中插入1个组框(“请选择你的兴趣爱好:”),4个复选框(“足球”、“篮球”、“排球”、“游泳”)
// 在IDD_PROP3中插入1个组合框(组合框结合了编辑框和列表,有3种类型的组合框:Dropdown、Drop List(无法编辑)、Simple(列表始终显示))设置为Drop List,1个静态文本(“请选择你的薪资水平:”)
// 为这3个属性页资源生成对应的类(基类选择CPropertyPage):CProp1、CProp2和CProp3


(如果VC在增加了新类后出现“Unable to open the file...for class...”,新类本身是建立成功的,但ClassWizard没有这条信息,显示不出这个类,无法通过它来增加消息响应和成员变量等。解决方法是保存工程文件,关闭工程,找到工程目录下的“工程名.clw”,这个文件存储了ClassWizard使用的信息,删除它,打开工程,选择ClassWizard,提示数据库文件不存在,从源文件重新建立,输入新的数据库文件名,重建数据库后即可恢复)

// CPropertyPage(属性表单类)从CDialog派生,要使用属性表单,创建属性表单对象,将每个CPropertyPage(属性页)对象用CPropertySheet::AddPage函数加入到属性表单中,之后调用CPropertySheet::DoModal显示模态属性表单,用CPropertySheet::Create创建非模态属性表单
// 用ClassWizard插入一个新的类(CPropSheet),基类选择CPropertySheet
// 在CPropSheet中增加3个属性页的成员变量,当然需要包括3个属性页的头文件(以便知道其类型定义)

// PropSheet.h
...
#include "Prop1.h"
#include "Prop2.h"
#include "Prop3.h"

class CPropSheet : public CDialog
{
...
public:
CProp1 m_prop1;
CProp2 m_prop2;
CProp3 m_prop3;
...
};

// 在CPropSheet的构造函数中将3个属性页增加到属性表单中,在CPropSheet的2个构造函数中都需要处理

// PropSheep.cpp
...
CPropSheet::CPropSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) // 这个构造函数是利用ID号标识,第2个参数是父窗口(通常是应用程序框架窗口),第3个参数是缺省的属性页
:CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
AddPage(&m_prop1);
AddPage(&m_prop2);
AddPage(&m_prop3);
}

CPropSheet::CPropSheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) // 这个构造函数是利用字符串指针标识
:CPropertySheet(pszCaption, pParentWnd, iSelectPage)
{
AddPage(&m_prop1);
AddPage(&m_prop2);
AddPage(&m_prop3);
}

// 增加菜单项(IDM_PROPERTYSHEET),在View类中增加消息响应函数OnPropertysheet

#include "PropSheet.h" // 包含属性表单类的头文件

void CXXXView::OnPropertysheet()
{
CPropSheet propSheet("维新属性表单程序"); // 属性表单对象,设定标题,后2个参数用缺省值

propSheet.DoModal(); // 显示模态属性表单(虽然CPropertySheet派生自CWnd类,但还是有DoModal函数的)
}

// 如果显示的属性页出现乱码,则用资源编辑器将属性页的语言改为“中文”,对话框字体改为“宋体”


向导对话框的编程:

// 创建向导对话框和属性表单是同样的步骤,但在DoModal前需要调用SetWizardMode,用SetWizardButtons使能
// 重写OnPropertysheet

void CXXXView::OnPropertysheet()
{
CPropSheet propSheet("维新属性表单程序");
propSheet.SetWizardMode(); // 设置为向导模式
propSheet.DoModal();
}

// 在属性页中增加OnSetActive函数以设置各页面显示时属性表单的按钮(上一步、下一步、完成)
// OnSetActive在CPropertyPage中是一个虚函数,只要在派生类增加这个虚函数即可

// 增加CProp1中的OnSetActive(注意是用Class View增加虚函数Virtual Function)

BOOL CProp1::OnSetActive()
{
((CPropertySheet)GetParent())->SetWizardButtons(PSWIZB_NEXT); // 由于CPropertySheet类对象是CProp1等属性页的父窗口(在用AddPage函数增加属性页时关联?),因此调用GetParent获取其指针(但由于GetParent返回CWnd指针,需要用(CPropertySheet)做强制类型转换),再调用SetWizardButtons设置每个属性页的属性表单按钮(这里设置为只有“下一步”按钮,因为这是向导的第一页)
return CPropertyPage::OnSetActive();
}

// 增加CProp2中的OnSetActive

BOOL CProp2::OnSetActive()
{
((CPropertySheet)GetParent())->SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT); // 这里设置为“上一步”按钮和“下一步”按钮,因为这是第二页,同时还有第三页
return CPropertyPage::OnSetActive();
}

// 增加CProp3中的OnSetActive

BOOL CProp3::OnSetActive()
{
((CPropertySheet)GetParent())->SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH); // 这里设置为“上一步”按钮和“完成”按钮,因为这是最后一页
return CPropertyPage::OnSetActive();
}

// 向导对话框的特殊情况:在用户尚未作出选择前,不允许进入下一步
// 关联Prop1上的单选按钮和一个成员变量
// 先将第一个单选按钮(IDC_RADIO1)设置为Group属性(Group属性能将几个单选按钮设为一组,当用户选择其中某个单选按钮时,关联的成员变量会被赋予不同的值,第一个为0,以此类推。一个Group属性的单选按钮会将其后所有没有Group属性的单选按钮都视为同自己一个组)(用资源编辑器操作)
// 双击该单选按钮,弹出ClassWizard(当提示是否要新建一个类时,选择否),对IDC_RADIO1增加一个整形(int)的成员变量(m_occupation)
// 系统会将m_occupation初始化为-1,也就是三个单选按钮全都不选,那么可以据此判断用户是否已经选择了单选按钮
// 应该在当用户点击按钮进入下一步时判断是否已经作出了选择

// 在CProp1属性页中增加一个虚函数OnWizardNext(这个函数在“下一步”按钮被点击时调用)

LRESULT CProp1::OnWizardNext()
{
UpdateData(TRUE); // 读取控件的值到关联的变量

if (m_occupation == -1) // 如果m_occupation是-1,表示用户还没有选择
{
MessageBox("请选择你的职业!");
return -1; // 让OnWizardNext返回-1,不要转到“下一步”
}
return CPropertyPage::OnWizardNext();
}

// 在CProp1属性页的工作地点列表框中加入一些内容
// 增加对WM_INITDIALOG的消息处理函数

BOOL CProp1::OnInitDialog()
{
CPropertyPage::OnInitDialog();

((CListBox*)GetDlgItem(IDC_LIST1))->AddString("北京"); // 如果不增加关联的成员变量,则采用GetDlgItem函数获取控件的指针(注意:GetDlgItem返回CWnd指针,需要用(CListBox*)强制类型转换),然后调用AddString成员函数增加列表框的内容
((CListBox*)GetDlgItem(IDC_LIST1))->AddString("天津");
((CListBox*)GetDlgItem(IDC_LIST1))->AddString("上海");

return TRUE;
}

// 判断用户是否选择了一个工作地点,是不是允许进入“下一步”
// 对IDC_LIST1创建一个关联的CString类型的成员变量m_workAddr(用ClassWizard操作)
// 扩展OnWizardNext函数

LRESULT CProp1::OnWizardNext()
{
UpdateData(TRUE);

if (m_occupation == -1)
{
MessageBox("请选择你的职业!");
return -1;
}

if (m_workAddr == "") // 如果m_workAddr为空,则表明用户还没有选择工作地点
{
MessageBox("请选择你的工作地点!");
return -1;
}

return CPropertyPage::OnWizardNext();
}

// 在CProp2中增加4个对应控件的BOOL类型的成员变量m_football、m_basketball、m_volleyball和m_swim,系统会将它们在CProp2的构造函数中初始化为FALSE
// 增加虚函数OnWizardNext

LRESULT CProp2::OnWizardNext()
{
UpdateData(TRUE); // 读取控件的值到关联的变量

if (m_football || m_basketball || m_volleyball || m_swim) // 如果有任何一个复选框被选择
{
return CPropertyPage::OnWizardNext(); // 就让用户转到“下一步”
}
else
{
MessageBox("请选择你的兴趣爱好!");
return -1; // 让OnWizardNext返回-1,不要转到“下一步”
}
}

// 在CProp3属性页的组合框IDC_COMBO2中加入一些内容
// 同样增加对WM_INITDIALOG的消息处理函数
// 应取消IDC_COMBO2中Sort属性,否则会将加入的内容自动排序

BOOL CProp3::OnInitDialog()
{
CPropertyPage::OnInitDialog();

((CComboBox*)GetDlgItem(IDC_COMBO2))->AddString("1000元以下"); // 同样调用GetDlgItem函数获取控件的指针(注意:GetDlgItem返回CWnd指针,需要用(CComboBox*)强制类型转换),然后调用AddString成员函数增加组合框的内容
((CComboBox*)GetDlgItem(IDC_COMBO2))->AddString("1000-2000元");
((CComboBox*)GetDlgItem(IDC_COMBO2))->AddString("2000-3000元");
((CComboBox*)GetDlgItem(IDC_COMBO2))->AddString("3000元以上");

((CComboBox*)GetDlgItem(IDC_COMBO2))->SetCurSel(0); // 调用SetCurSel选择第1个选项(参数是以0为基础的索引号)

return TRUE;
}

// 在View类显示用户所有的选择
// 为了让View类能够获取用户选择的工资水平,在CProp3中增加一个CString类型的成员变量m_strSalary(public)存放用户选择的工资水平(字符串,而不是索引号)
// 在CProp3中增加虚函数OnWizardFinish,当用户按下“完成”按钮后读取选择

BOOL CProp3::OnWizardFinish()
{
int index;
index = ((CComboBox*)GetDlgItem(IDC_COMBO2))->GetCurSel(); // 调用GetCurSel获取CComboBox类选择的索引号(以0为基础)
((CComboBox*)GetDlgItem(IDC_COMBO2))->GetLBText(index, m_strSalary); // 调用GetLBText获取字符串(第一个参数是索引号,第二个参数是接收输出的字符串)

return CPropertyPage::OnWizardFinish();
}

// 在View类中增加对应的成员变量,并在构造函数中对它们进行初始化

class CXXXView : public CView
{
...
private:
int m_iOccupation;
CString m_strWorkAddr;
BOOL m_bLike[4];
CString m_strSalary;
...
}

CXXXView::CXXXView()
{
m_iOccupation = -1;
m_strWorkAddr = "";
memset(m_bLike, 0, sizeof(m_bLike));
m_strSalary = "";
}

// 在View类中判断用户最终以“完成”(IDWIZFINISH)还是“取消”(IDCANCEL)按钮关闭了向导

void CXXXView::OnPropertysheet()
{
CPropSheet propSheet("维新属性表单程序");
propSheet.SetWizardMode(); // 设置为向导模式
if (propSheet.DoModal() == IDWIZFINISH) // 虽然DoModal后属性表单窗口已被销毁,但属性表单对象的生命周期还未结束,所以能够访问其内部的数据成员
{
m_iOccupation = propSheet.m_prop1.m_occupation; // 从属性表单对象获取其成员变量的值
m_strWorkAddr = propSheet.m_prop1.m_workAddr;
m_bLike[0] = propSheet.m_prop2.m_football;
m_bLike[1] = propSheet.m_prop2.m_basketball;
m_bLike[2] = propSheet.m_prop2.m_volleyball;
m_bLike[3] = propSheet.m_prop2.m_swim;
m_strSalary = propSheet.m_prop3.m_strSalary;

Invalidate(); // 调用Invalidate将窗口无效,引起重绘,在OnDraw函数中输出信息
}
}

void CXXXView::OnDraw(CDC* pDC)
{
CXXXDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

CFont font; // 设置输出字体
font.CreatePointFont(300, "华文行楷");
CFont *pOldFont;
pOldFont = pDC->SelectObject(&font);

CString strTemp;
strTemp = "你的职业:"; // 输出职业信息

switch (m_iOccupation)
{
case 0:
strTemp += "程序员";
break;
case 1:
strTemp += "系统工程师";
break;
case 2:
strTemp += "项目经理";
break;
default:
break;
}
pDC->TextOut(0, 0, strTemp); // 在第1行输出

strTemp = "你的工作地点"; // 输出工作地点
strTemp += m_strWorkAddr;

TEXTMETRIC tm; // 获取字体的高度
pDC->GetTextMetrics(&tm);
pDC->TextOut(0, tm.tmHeight, strTemp); // 在第2行输出

strTemp = "你的兴趣爱好:"; // 输出兴趣爱好
if (m_bLike[0])
{
strTemp += "足球 "; // 由于兴趣爱好是多选,累加在一个输出中,在字符串最后加一个空格将它们隔开
}

if (m_bLike[1])
{
strTemp += "篮球 ";
}

if (m_bLike[2])
{
strTemp += "排球 ";
}

if (m_bLike[3])
{
strTemp += "游泳 ";
}
pDC->TextOut(0, tm.tmHeight * 2, strTemp); // 在第3行输出

strTemp = "你的薪资水平:"; // 输出薪资水平
strTemp += m_strSalary;
pDC->TextOut(0, tm.tmHeight * 3, strTemp); // 在第4行输出

pDC->SelectObject(pOldFont); // 不要忘记将原字体恢复
}

  评论这张
 
阅读(355)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017