VC++中属性页(向导)的实现 (学习孙鑫老师视频笔记)

来源:互联网 发布:codeblocks linux 编辑:程序博客网 时间:2024/06/05 20:31

我们已经非常熟悉软件安装的步骤,一般都是由用户协议、安装位置、安装选项、安装这几个过程构成。其中,I agree、next、back、finish、cancel这几项是必不可少的。那么这个安装程序(仅仅指这个安装过程的界面)是怎么做出来的呢?MFC给我们提供了很方便的方法。

其实,我们看到的每一个步骤,都是一个属性页(CPropertyPage),而几个属性页构成一个属性表(CpropertySheet)。这个属性表是一个整体,根据需要,它可以初始化为一个类似于安装向导的界面,也可以初始化为一个类似于标签页的界面。

本例子是一个类似于安装向导的界面。

这个程序开发的步骤如下:

1、 我们首先新建一个MFC工程,工程名字为“PropertyPageDemo”,选择单文档模式,其它保持默认。完成之后编译运行一下看是否有错误,没错进行第二步,否则检查错误,重新建立工程。

2、 打开资源视图(ResourceView)的对话框目录(Dialog),在“Dialog”上右键、选择insert,在弹出的对话框中选择Dialog下的IDD_PROPPAGE_MEDIUM[English(U.S)]、点击new,这样我们就创建了一个新的属性页。按照此方法我们再创建两个属性页。

3、 在ResoureceView中右键新建的属性页,选择属性,在弹出的对话框中修改资源的ID为:IDD_PROP1、IDD_PROP2、IDD_PROP3,语言调整为Chinese(P.R.C.)。(在弹出的对话框上点左上角的图钉样子的图标可以保持当前对话框的可见性,使得在调整完一个资源属性之后不用关闭对话框,再点另外一个资源,对话框将自动切换成新资源的属性)。

4、 设置属性页:将属性页一、二、三的标题分别修改成第一步、第二步、第三步。

5、 将属性页一中原来的提示删除,添加一个Group Box控件,将Group Box标题修改为“职位”;然后在Group Box中添加三个Radio Button,将标题分别修改为“程序员”、“系统架构师”、“系统分析师”。添加一个静态文本标记(statictext)和一个List Box,将List Box属性中style的sort取消(这样保证不对选项进行排序,从而得到与输入一致的结果)。

6、 将属性页二中原来的提示删除,添加一个Group Box,标题为“爱好”;然后添加四个复选框(Check Box),分别为“足球”、“篮球”、“排球”、“游泳”。

7、 将属性页三中原来的提示删除,添加一个静态文本,标题为“薪资水平”;然后添加一个下拉列表(Combo Box),将其属性中style的sort取消。这样基本的界面已经做出来了。

8、 在新建的界面上右键、选择class wizard,新建类“CProp1”、“CProp2”、“CProp3”,基类为“CPropertyPage”。

9、 新建一个类,名字为“CPropSheet”,基类为CPropertySheet。这个类相当于CPropertyPage的容器。在CPropSheet的构造函数中添加CProp1、CProp2、CProp3的对象,使得CPropertyPage放入“容器”。过程:

a) 首先添加三个成员变量,CProp1 m_prop1、CProp2 m_prop2、CProp3 m_prop3,public属性;

b) 在构造函数中:

this->AddPage(&m_prop1);this->AddPage(&m_prop2);this->AddPage(&m_prop3);

需要注意的是,CPropSheet有两个构造函数,需要在每个构造函数中都添加属性页。

10、在资源视图中找到菜单(MENU),打开,新建一个子菜单,标题为程序,取消其popup属性,设置ID为:ID_SHEET。右键“程序”,选择classwizard,添加一个消息相应函数,对应“CPropertyPageDemoView类”,函数默认为“OnSheet()”

11、针对OnSheet(),编写代码

a) 我们首先需要将sheet显示出来(这时候的sheet已经拥有了属性页)。

CPropSheet sheet("职业选择");//构造一个sheet

sheet.SetWizardMode();//设置成“下一步模式”否则是标签页形式

sheet.DoModal();//以模态形式显示sheet

12、此时我们发现已经每个属性页都有了“上一步”、“下一步”、“取消”这三个按钮。但是在第一个属性页中显示“上一步”和在第三个属性页中显示“下一步”是错误的,接下来我们要处理这个问题

a) 在”CProp1”这个类上面右键选择add Virtual Function这项,选中里面的OnSetActive,编辑代码:在里面:

这里面用到了SetWizardButtons这个函数,但是msdn上面的说明是这个函数只能用CPropertySheet来调用,所以我们使用GetParent()这个函数获取CPropertySheet的一个指针,适用指针来操作SetWizardButtons这个函数。

((CPropertySheet*)this->GetParent())->SetWizardButtons(PSWIZB_NEXT);

b) 同样我们修改第二、三个属性页:

((CPropertySheet*)this->GetParent())->SetWizardButtons(PSWIZB_BACK|PSWIZB_NEXT);

((CPropertySheet*)this->GetParent())->SetWizardButtons(PSWIZB_FINISH);

13、设置第一个属性页“职位”项的数据和页面数据校验。

a) 把RadioButton的“group”属性,然后右键选择class wizard选择Member Variables

在看到的是IDC_RADIO1,点右边按钮“Add Variable”,依次设置为m_occupation、value、int;

b) 按照上面的办法设置ListBox,其中使用到的数据是:IDC_LIST1,变量是m_workAddr,value、CString;

c) 设置RadioButton组的校验:

i. 当我们在点击“下一步”这个按钮的时候触发一个函数“OnWizardNext()”,这个函数的添加方法和12 a)的方式一样;

ii. 接下来首先更新数据this->UpdateData();使得m_occpution获取值;

iii. 判断接受到的值m_occupation, 如果一组RadioButton有被选中的项的话,返回被选中的项的索引,这个索引从0开始计数;如果没有选择的话返回-1;

If(m_occupation==-1)

{

MessageBox(“请选择职位!”);

return -1;//如果返回-1则不会执行“下一步”

}

14、设置第一个属性页“工作地点”项的数据和页面数据校验。

a) 完善“工作地点项”的数据:首先为“CProp1”这个类添加一个消息响应函数OnInitDialog(),保证在初始化属性页的时候进行数据的初始化,然后

((CListBox*)this->GetDlgItem(IDC_LIST1))->AddString("上海");

((CListBox*)this->GetDlgItem(IDC_LIST1))->AddString("北京");

((CListBox*)this->GetDlgItem(IDC_LIST1))->AddString("成都");

这样完成数据的初始化

b) 在OnWizardNext()函数中判断时候选择“工作地点”中的值

If(m_workAddr==””)

{

MessageBox(“请选择工作地点!”);

return -1;

}

c) 完成之后14、15步的代码:

LRESULT CProp1::OnWizardNext()

{

// TODO: Add your specialized code hereand/or call the base class

this->UpdateData();

if(m_occupation==-1)

{

MessageBox("请选择职位!");

return -1;

}

if(m_workAddr=="")

{

MessageBox("请选择工作地点!");

return -1;

}

return CPropertyPage::OnWizardNext();

}

15、设置第二个属性页的数据和数据校验

a) 首先关联变量:将各项均关联成BOOL型的m_basketball、m_football、m_swim 、m_volleyball

b) 在OnWizardNext()函数中先更新数据,再判断,若是四个成员变量之中有一个为真,则可以进行“下一步”,否则提示,并保持当前属性页

c) 代码

LRESULT CProp2::OnWizardNext()

{

// TODO: Add your specialized code hereand/or call the base class

this->UpdateData();

if(m_basketball || m_football || m_swim ||m_volleyball)

{

return CPropertyPage::OnWizardNext();

}

else

{

MessageBox("请选择爱好!");

return -1;

}

}

16、设置第三个属性页的数据和数据校验

a) 将ComboBox关联CString类型变量m_salary

b) 初始化数据:

BOOL CProp3::OnInitDialog()

{

CPropertyPage::OnInitDialog();

// TODO: Add extra initialization here

((CComboBox*)this->GetDlgItem(IDC_COMBO1))->AddString("1000元以下");

((CComboBox*)this->GetDlgItem(IDC_COMBO1))->AddString("1000-3000元");

((CComboBox*)this->GetDlgItem(IDC_COMBO1))->AddString("3000元以上");

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

// EXCEPTION: OCX Property Pages shouldreturn FALSE

}

c) 校验数据

BOOL CProp3::OnWizardFinish()

{

// TODO: Add your specialized code hereand/or call the base class

this->UpdateData();

if(m_salary=="")

{

MessageBox("请选择薪资水平!");

return FALSE;

}

return CPropertyPage::OnWizardFinish();

}

至此我们完成了全部属性页的数据初始化和校验工作

17、在View中打印选择的结果

a) 定义四个变量,接受属性页中的值CString m_strSalary、int m_iOccupation、BOOL m_bHobby[4]、CString m_strWorkAddr

b) 在View的构造函数中初始化这四个变量

m_iOccupation=-1;

m_strWorkAddr="";

m_strSalary="";

memset(m_bHobby,0,sizeof(m_bHobby));//这个函数m_bHobby[4]初始化为假

c) 判断sheet.DoModal()的返回值,若是正常结束则开始接受传回来的值

if(ID_WIZFINISH ==sheet.DoModal())

{

m_strSalary=sheet.m_prop3.m_salary;

m_strWorkAddr=sheet.m_prop1.m_workAddr;

m_iOccupation=sheet.m_prop1.m_occupation;

m_bHobby[0]=sheet.m_prop2.m_football;

m_bHobby[1]=sheet.m_prop2.m_basketball;

m_bHobby[2]=sheet.m_prop2.m_swim;

m_bHobby[3]=sheet.m_prop2.m_volleyball;

this->Invalidate();//将view设置无效,引起窗口重绘

}

18、在View中输出选择的结果

a) 由于我们需要将结果呈现在View中,并且不因窗口的变化而消失,所以我们将输出写在OnDraw()中,可以使得每一次重绘都能重新输出结果

b) 代码如下:

void CPropertyPageDemoView::OnDraw(CDC*pDC)

{

CPropertyPageDemoDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

// TODO: add draw code for native data here

CString strTmp="";

strTmp="职业:";

if(m_iOccupation==0)

{

strTmp+="程序员";

}

if(m_iOccupation==1)

{

strTmp+="系统架构师";

}

if(m_iOccupation==2)

{

strTmp+="系统分析师";

}

pDC->TextOut(0,0,strTmp);

TEXTMETRIC tm;

pDC->GetTextMetrics(&tm);//获得当前字体高度

strTmp="工作地点:";

pDC->TextOut(0,tm.tmHeight,strTmp+m_strWorkAddr);

strTmp="爱好:";

if(m_bHobby[0])

{

strTmp+="足球 ";

}

if(m_bHobby[1])

{

strTmp+="篮球 ";

}if(m_bHobby[2])

{

strTmp+="游泳 ";

}

if(m_bHobby[3])

{

strTmp+="排球";

}

pDC->TextOut(0,tm.tmHeight*2,strTmp);

strTmp="薪资水平:";

pDC->TextOut(0,tm.tmHeight*3,strTmp+m_strSalary);

}


0 0
原创粉丝点击