分享
 
 
 

用VC++创建自定义向导程序

王朝vc·作者佚名  2006-01-17
窄屏简体版  字體: |||超大  

用VC++创建自定义向导程序

作者:毛翔 网站:esword.onchina.net

下载本文源代码

向导是一种用来简化用户操作的程序。在Microsoft 的所有产品中都存在向导,如Office2000 中的Web 页向导就是一个十分典型的向

导(如下图所示),还有常用的VC++向导。

一个基本的向导程序应该包含以下几个基本按钮: 取消、上一步、下一步、完成、帮助。

一、标准向导程序

在 VC++中,可以使用类CPropertySheet和类CPropertyPage方便地编写一个向导程序。

首先我们来介绍一下类CPropertySheet 和类CPropertyPage。

1. 类CPropertyPage 是从CDiaglog中派生出来的,具有Diaglog的基本性质,需要注意的是它的样式必须是Child。

2. 类CPropertySheet 是一个属性表,也是一个窗体,相当一个容器,用来存放所有的CpropertyPage。它不是 从CDialog

派生出来的,但是它可以象普通对话框类似的操作, 如DoModal(),当用 DoModal()显示 后,它就包含了“取消”、“上一步”、“下一步”

等基本按钮。

下面给出一个实例

① 新建一个 VC++ MFC AppWizard 工程,命名为TraditionalWizard,并选择Dialog Based 样式。

② 在自动生成 的Dialog 资源中加入一个按钮IDC_BENGINWIZ 用来启动向导。

③ 创建 CPropertyPage。新建Dialog 资源,命名为IDD_STEP1,注意一定要将新建对话框的Style属性设置成Child

和边界属性设置为Thin,并且不要生成一个新类。

用ClassWizard 生成一个新类,命名为CStep1,基类为CPropertyPage,且将Dialog ID 设置为刚生成的资源IDD_STEP1。这样就生成了一个新属性页Step1。如此操作就可以

同样生成Step2、Step3 属性页。为了方便显示,在每个对话框都放置了一个控件,用来表示当前是哪一步。

④ 创建 CPropertySheet。新建一个类,命名为CWizard,基类为CPropertySheet。并将属性页和属性表关联起来。代码为

//将代码放在按钮IDC_BEGINWIZ的Click事件中

CWizard MyWizard(_T("我的向导 "),this,1); //生成一个属性表

CStep1 MyStep1; //属性页1

CStep2 MyStep2; //属性页2

CStep3 MyStep3; //属性页3

MyWizard.AddPage(&MyStep1); //添加属性页1

MyWizard.AddPage(&MyStep2); //添加属性页2

MyWizard.AddPage(&MyStep3); //添加属性页3

MyWizard.SetWizardMode(); //将属性表设置成向导样式

MyWizard.SetActivePage(&MyStep1); //设置第一页为第一步

MyWizard.DoModal(); //显示属性表

⑤协调显示。在每一页为当前页时,都会触发OnSetActive事件,故对每一个属性页都要重载该函数,在CStep1类上选择Add Virtual

Function ...。因为显示第一页时,不存在“上一步”,故在CStep1的 OnSetActive函数中需要添加如下代码:

//代码放在OnSetActive函数中

CPropertySheet* pParent=(CPropertySheet*)GetParent(); // 获得属性表的指针

pParent-SetWizardButtons(PSWIZB_NEXT); // 设置属性表的显示按钮只为下一步

SetDlgItemText(IDC_TEXT1,"这是向导的第一步");

同样在显示中间页时应该设置成即有“上一步”,也有“下一步”,代码为:

CPropertySheet* pParent=(CPropertySheet*)GetParent();

pParent-SetWizardButtons(PSWIZB_NEXT|PSWIZB_BACK);

SetDlgItemText(IDC_TEXT2,"这是向导的第二步");

最后在显示最后一页时只显示“完成”和“上一步”,代码为:

CPropertySheet* pParent=(CPropertySheet*)GetParent();

pParent-SetWizardButtons(PSWIZB_FINISH|PSWIZB_BACK);

SetDlgItemText(IDC_TEXT3,"这是向导的第三步");

这样一个基本的向导程序就完成了,其效果如图所示

二、自定义向导程序

通过上面的例子,我们不难发现标准的向导基本能满足要求,但仍然存在一些缺陷:

1.不能改变向导按钮的样式,如想在“上一步”、“下一步就”按钮上添加图标

2.不能象上面的Web向导一样有个“完成”按钮进行默认设置

3.不能修改向导按钮的位置

上述缺陷是因为我们采用了CPropertySheet类,而CPropertySheet类不是一个可修改的资源。

为了达到个性化向导的目的,我们可以不使用CPropertySheet类和CPropertyPage类。

设计的基本思路:

1. 采用标准的向导的工作方式。每一步就是一个对话框,向导本身也是一个对话框,用来容纳每步对话框.

2. 每步的对话框应 该没有Title、没有边界、样式为Child,当点击“下一步”或“上一步”时,将这个 对话框定位到要显示的位置。

3. 因为向导一般都包含很多步,为了管理这些页,我们可以创建一个链表来管理每一步的对话框。

4. 为了方便对话框定位,可以事先定义好位置。

三、自定义向导的实现

1. 工程的建立与基本界面的生成

生成一个MFC APPWIZARD 新工程,命名为CustomWizard,在Step1 中选择基于Dialog Based样式。

在自动生成的Dialog 资源中加入一个按钮IDC_BENGINWIZ 用来启动向导。

新建一个对话框 资源,命名为IDC_WIZARD,用来显示自定义向导界面,如图

依次创建向导的每页 的对话框资源,命名为IDD_STEP1,IDD_STEP2,IDD_STEP3,

(图4)

2. 生成所需要的类

为了方便叙述,表1将所用的类进行了归纳

(表1)

类名

基类

说明

CWizard

CDialog

向导的框架

CStep1

CDialog

向导的第一步

CStep2

CDialog

向导的第二步

CStep3

CDialog

向导的第三步

CCustomWizardDlg

CDialog

启动向导

3. 在CWizard添加要使用的数据结构

为了方便描述,表2列出了使用到的成员变量

(表2)

成员变量

类型

说明

rectPage

CRect

每页显示的范围

nPageCount

UINT

页的总数

nCurrentPage

UINT

正在显示的页

nPageLink

PAGELINK*

用来链接所有的页

typedef struct PAGELINK{

UINT nNum;

CDialog* pDialog;

struct PAGELINK* Next;};

nNum为页的编号

pDialog为页所对应的对话框的指针

4. CWizard所使用到的函数 添加一个新页到Wizard框架,入口参数为要添加的对话框指针和ID

void CWizard::AddPage(CDialog* pDialog, UINT nID)

{

struct PAGELINK* pTemp = pPageLink;

//插入新生成的结点

struct PAGELINK* pNewPage = new PAGELINK;

pNewPage-pDialog = pDialog;

pNewPage-pDialog-Create(nID,this); // 以无模式创建窗口

ASSERT(::IsWindow(pNewPage-pDialog-m_hWnd));

// 检查每页的样式

DWORD dwStyle = pNewPage-pDialog-GetStyle();

ASSERT((dwStyle & WS_CHILD) != 0); // 子窗口

ASSERT((dwStyle & WS_BORDER) == 0); // 无边界

// 显示

pNewPage-pDialog-ShowWindow(SW_HIDE); //先隐藏,需要时再显示

pNewPage-pDialog-MoveWindow(rectPage);

//移动对话框到制定位置,rectPage已经初始化了

pNewPage-Next=NULL;

pNewPage-nNum=++nPageCount; //计数器加1

if (pTemp) //插入到链表

{ //如果不是空链表

while (pTemp-Next) pTemp=pTemp-Next; // 移动链表末尾

pTemp-Next=pNewPage;

}

else // 空链表

pPageLink=pNewPage; //若是第一个节点

}

显示的页,入口参数为要显示的某特定页的编码

void CWizard::ShowPage(UINT nPos)

{

struct PAGELINK* pTemp=pPageLink;

while(pTemp)

{

if(pTemp-nNum==nPos)

{

pTemp-pDialog-ShowWindow(SW_SHOW);

}

else

//不显示

pTemp-pDialog-ShowWindow(SW_HIDE);

pTemp=pTemp-Next;

}

if (nPos=nPageCount) //最后一页

{

nCurrentPage=nPageCount;

SetWizButton(2);

return;

}

if (nPos<=1) //首页

{

nCurrentPage=1;

SetWizButton(0);

return;

}

//如果是中间步

SetWizButton(1);

}

为了与显示统一,需要相应的设置按钮

void CWizard::SetWizButton(UINT uFlag)

{

GetDlgItem(IDC_CANCEL)-EnableWindow(TRUE);

GetDlgItem(IDC_PREV)-EnableWindow(TRUE);

GetDlgItem(IDC_NEXT)-EnableWindow(TRUE);

GetDlgItem(IDC_FINISH)-EnableWindow(TRUE);

switch(uFlag)

{

case 0: //第一步

GetDlgItem(IDC_PREV)-EnableWindow(FALSE);

break;

case 1: //中间步

break;

case 2: //最后一步

GetDlgItem(IDC_NEXT)-EnableWindow(FALSE);

break;

}

}

点击“上一步”、“下一步”、“完成”、“取消”代码

void CWizard::OnPrev()

{

// TODO: Add your control notification handler code here

ShowPage(--nCurrentPage);

}

void CWizard::OnNext()

{

// TODO: Add your control notification handler code here

ShowPage(++nCurrentPage);

}

void CWizard::OnFinish()

{

// TODO: Add your control notification handler code here

AfxMessageBox("采用默认值完成向导");

CDialog::OnOK();

}

void CWizard::OnCancel()

{

// TODO: Add your control notification handler code here

if (AfxMessageBox(IDS_QUIT,MB_OKCANCEL|MB_ICONQUESTION)==IDCANCEL)

return;

CDialog::OnCancel();

}

5. 辅助代码,如初始化等

BOOL CWizard::OnInitDialog()

{

CDialog::OnInitDialog();

//获得每页显示的范围

CRect Rect1;

GetWindowRect(&Rect1); // 获得主窗口的位置

int nCaption = ::GetSystemMetrics(SM_CYCAPTION); // 系统Title高度

int nXEdge = ::GetSystemMetrics(SM_CXEDGE);

int nYEdge = ::GetSystemMetrics(SM_CYEDGE);

CRect Rect2;

GetDlgItem(IDC_POS)-GetWindowRect(&Rect2); // 获得框架的位置

Rect1.top=Rect1.top+nCaption+nYEdge; // 相对坐标

Rect1.left=Rect1.left+2*nXEdge;

//计算机位置

rectPage.top=Rect2.top-Rect1.top;

rectPage.left=Rect2.left-Rect1.left;

rectPage.bottom=Rect2.bottom-Rect1.top;

rectPage.right=Rect2.right-Rect1.left;

//页示的添加要显

CStep1* pStep1 = new CStep1;

CStep2* pStep2 = new CStep2;

CStep3* pStep3 = new CStep3;

AddPage(pStep1, IDD_STEP1);

AddPage(pStep2, IDD_STEP2);

AddPage(pStep3, IDD_STEP3);

//显示第一页

ShowPage(1);

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

// EXCEPTION: OCX Property Pages should return FALSE

}

因为是无模式窗体,所以要自己销毁窗体

void CWizard::OnDestroy()

{

CDialog::OnDestroy();

// TODO: Add your message handler code here

//每页依次消除

struct PAGELINK* pTemp=pPageLink;

while(pTemp)

{

struct PAGELINK* pNextTemp = pTemp-Next;

pTemp-pDialog-DestroyWindow();

delete pTemp-pDialog;

delete pTemp;

pTemp = pNextTemp;

}

}

6. 启动向导需要在IDC_BEGINWIZ 按钮的Click事件中加入下列代码:

CWizard MyWiz; //显示向导

MyWiz.DoModal();

四、测试

上述两个程序在Win2000、VC++ 6.0 下编译通过。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有