孙鑫vc视频教程笔记(一) 之 VC++ MFC属性页使用说明

VC++ MFC属性页使用说明

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

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

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

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

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

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

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

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

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

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

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

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

a)         首先添加三个成员变量,CProp1 m_prop1CProp2 m_prop2CProp3 m_prop3public属性;

b)         在构造函数中:

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

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

10、 在资源视图中找到菜单(MENU),打开,新建一个子菜单,标题为程序,取消其popup属性,设置ID为:ID_SHEET。右键“程序”,选择class wizard,添加一个消息相应函数,对应“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_occupationvalueint

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

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)         完成之后1415步的代码:

LRESULT CProp1::OnWizardNext()

{

         // TODO: Add your specialized code here and/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_basketballm_footballm_swim m_volleyball

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

c)         代码

LRESULT CProp2::OnWizardNext()

{

          // TODO: Add your specialized code here and/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 TRUE unless you set the focus to a control

                        // EXCEPTION: OCX Property Pages should return FALSE

}

c)         校验数据

BOOL CProp3::OnWizardFinish()

{

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

          this->UpdateData();

          if(m_salary=="")

          {

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

                   return FALSE;

          }

          return CPropertyPage::OnWizardFinish();

}

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

17、 View中打印选择的结果

a)         定义四个变量,接受属性页中的值CString m_strSalaryint m_iOccupationBOOL 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);

         

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值