前言
倒也没啥特别,效果是类似于一个问卷调查。
正文
直接在前面项目上改动了
点击这个按钮,自然是弹出新的对话框,所以要新建资源
右击资源视图中该项目的Dialog,选择添加资源
这个对话框类型后面仨就是大小之间有差异。
然后就是拖控件,其中这些radio单选框啥啥啥的,以前html做表单的时候用的感觉都差不多吧,不算太陌生。
样式完成之后要新建类和这个对话框关联
这里要注意命名的时候要和Dialog里的一样,只不过我这个vs2022对话框id不知道为啥没显示,正常应该是会根据类名在前面加上IDD_,这也是为什么上面创建类名是这个样,但好在源文件头文件是随便的
创建完之后可以看到类向导这里这个类关联的资源就是刚才新建的对话框
类和对话框关联之后,就要给这些控件添加变量。
单选框的特性就是只能选中一个,那么这个变量首先为值类型,其次类型为BOOL。创建三个又太麻烦,所以新建一个之后直接改成数组
1 2 3
| public: BOOL m_lang[3];
|
在源文件中自然免不了修改了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
#include "pch.h" #include "RunningButton.h" #include "afxdialogex.h" #include "PROP01.h"
IMPLEMENT_DYNAMIC(PROP_01, CPropertyPage)
PROP_01::PROP_01() : CPropertyPage(IDD_PROP_01){ memset(m_lang, 0, sizeof(m_lang)); }
PROP_01::~PROP_01(){ }
void PROP_01::DoDataExchange(CDataExchange* pDX){ CPropertyPage::DoDataExchange(pDX); DDX_Radio(pDX, IDC_RADIO_CPP, m_lang[0]); DDX_Radio(pDX, IDC_RADIO_JAVA, m_lang[1]); DDX_Radio(pDX, IDC_RADIO_PYTHON, m_lang[2]); }
BEGIN_MESSAGE_MAP(PROP_01, CPropertyPage) END_MESSAGE_MAP()
|
在c/c++中布尔值本质就是0和1的表示,虽然TRUE真意是非0的值。
memset(m_lang, 0, sizeof(m_lang));
那么初始化的时候直接给这个数组全部写0,也就是表示FALSE,完成初始化的操作。
至于DDX_Radio(pDX, IDC_RADIO_CPP, m_lang[0]);
,就可以通过数组依次绑定。
这个里面应是得有几个公司的名字才对,由于这个类是我们新建的,还没有初始化的地方。
所以要重写InitDialog
老样子类视图选中然后属性里面找到重写选项,往下滑找到OnInitDialog
,点击后面add即可。
1 2 3 4 5 6 7 8 9
| BOOL PROP_01::OnInitDialog(){ CPropertyPage::OnInitDialog();
return TRUE; }
|
获取控件最快的就是用指针。
CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST_COMPANY);
因为这个控件是我们拖得,所以我们很清楚它是什么类型,但是别人不一定清楚。
而且GetDlgItem的返回类型是CWnd,但是好在CListBox是它的子类。所以直接强制转换一下。
获取完成后,就可以通过指针给他增加点字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| BOOL PROP_01::OnInitDialog(){ CPropertyPage::OnInitDialog();
CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST_COMPANY); if( pListBox ){ pListBox->AddString(_T("阿里巴巴")); pListBox->AddString(_T("华为")); pListBox->AddString(_T("腾讯")); pListBox->AddString(_T("百度")); pListBox->AddString(_T("京东")); }
return TRUE; }
|
这样这个对话框就ok了
再次创建新的对话框,拖动check box组合一下
同样的给这个对话框创建一个类,步骤也是从类向导开始,注意命名规范。
最后就是复选框添加变量,跟radio差不多的路数
1 2 3 4 5
| public: BOOL m_skill[4]; };
|
然后在源文件同样通过memset写0,和后面的绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| PROP_02::PROP_02() : CPropertyPage(IDD_PROP_02){
memset(m_skill, 0, sizeof(m_skill)); }
PROP_02::~PROP_02() { }
void PROP_02::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); DDX_Check(pDX, IDC_CHECK1, m_skill[0]); DDX_Check(pDX, IDC_CHECK2, m_skill[1]); DDX_Check(pDX, IDC_CHECK3, m_skill[2]); DDX_Check(pDX, IDC_CHECK4, m_skill[3]); }
|
这么一来这个对话框界面也就ok了。
可能稍微为了好看就要注意一下这几个对话框大小
选中这个dialog的时候vs的下面会显示,手动调整一下
至于这个也不做多解释了,创建的路数都一样。
唯一需要注意的是这个下拉多选的控件是combo box
数据使用分号分割,注意要英语符合。
最后三个对话框都创建好了,自然需要关联起来。
对这个项目创建一个MFC类。
1 2
| CMyProSheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); CMyProSheet(LPCTSTR pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0);
|
这两个构造函数可以看到就头不一样,UINT也就是unsigned int,下面那个也就是字符串
不过既然有俩了,那有啥改动就尽量都保持一样
然后添加一下我们三个对话框类
1 2 3 4
| public: PROP_01 m_prop1; PROP_02 m_prop2; PROP_03 m_prop3;
|
在源文件中构造的时候添加这三个页
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| CMyProSheet::CMyProSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) :CPropertySheet(nIDCaption, pParentWnd, iSelectPage) { AddPage(&m_prop1); AddPage(&m_prop2); AddPage(&m_prop3); }
CMyProSheet::CMyProSheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) :CPropertySheet(pszCaption, pParentWnd, iSelectPage) { AddPage(&m_prop1); AddPage(&m_prop2); AddPage(&m_prop3); }
|
那么这几个页是组合到一起了。剩下就是写那个按钮事件了。
额尴尬,跑的时候有个问题,就是单选按钮没有组,然后抛出异常了
修改一下
1 2 3 4 5 6 7 8 9 10 11 12
| PROP_01::PROP_01() : CPropertyPage(IDD_PROP_01) , m_lang(-1){ }
PROP_01::~PROP_01(){ }
void PROP_01::DoDataExchange(CDataExchange* pDX){ CPropertyPage::DoDataExchange(pDX); DDX_Radio(pDX, IDC_RADIO_CPP, m_lang); }
|
修改完之后跑起来就ok了
因为设置的大小差不多,比较和谐。
稍微有心的可能会注意到,那个帮助不一定需要,按照前面重载按钮类的示例,这边也就能重写
1 2 3 4 5 6 7 8
| BOOL PROP_01::OnSetActive(){
((CPropertySheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT); ((CPropertySheet*)GetParent())->GetDlgItem(IDHELP)->ShowWindow(SW_HIDE);
return CPropertyPage::OnSetActive(); }
|
1 2 3 4 5 6
| BOOL PROP_02::OnSetActive(){ ((CPropertySheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
return CPropertyPage::OnSetActive(); }
|
1 2 3 4 5 6
| BOOL PROP_03::OnSetActive(){ ((CPropertySheet*)GetParent())->SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH);
return CPropertyPage::OnSetActive(); }
|
第一个对话框,只显示下一步,上一步无法点击,并且隐藏帮助按钮
第二个对话框则上下都可行
第三个对话框只能向上一步和完成。
说到底还是个半成品,还有很多能优化的地方。
比如校验,目前这个即便不选择,也可以直接next。
所以要重写两个next,最后一个因为变成完成了,所以要重写的是finish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| LRESULT PROP_01::OnWizardNext(){ UpdateData(); if( m_lang == -1 ){ MessageBox(_T("请选择开发语言!"), _T("开发语言未选择"), MB_OK | MB_ICONERROR); return -1; }
if( m_company.GetLength() == 0 ){ MessageBox(_T("请选择公司!"), _T("公司未选择"), MB_OK | MB_ICONERROR); return -1; }
return CPropertyPage::OnWizardNext(); }
|
1 2 3 4 5 6 7 8 9 10 11
| LRESULT PROP_02::OnWizardNext(){ UpdateData();
if( (m_skill[0] + m_skill[1] + m_skill[2] + m_skill[3]) == 0 ){ MessageBox(_T("请选择技能!"), _T("技能未选择"), MB_OK | MB_ICONERROR); return -1; }
return CPropertyPage::OnWizardNext(); }
|
1 2 3 4 5 6 7 8 9 10 11
| BOOL PROP_03::OnWizardFinish(){ UpdateData();
if( m_money.GetLength() <= 0 ){ MessageBox(_T("请选择薪资!"), _T("薪资未选择"), MB_OK | MB_ICONERROR); return -1; }
return CPropertyPage::OnWizardFinish(); }
|
记得获取前肯定要更新一下数据
这套流程结束了之后,还要给用户一个反馈。
也只能加载打开按钮的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| void CRunningButtonDlg::OnBnClickedBtnQuery(){ CMyProSheet dlg(_T("职业调查"), this); dlg.SetWizardMode(); if( ID_WIZFINISH == dlg.DoModal() ){ CString strMsg = _T("您的选择是: "); switch( dlg.m_prop1.m_lang ){ case 0: strMsg += _T("开发语言: C++"); break; case 1: strMsg += _T("开发语言: Java"); break; case 2: strMsg += _T("开发语言: Python"); break; default: break; }
strMsg += _T("您的公司是: ") + dlg.m_prop1.m_company; strMsg += _T("您的技能有:"); CString strSkill[4] = { _T("网络编程"), _T("MFC"), _T("操作系统"), _T("数据结构") };
for( int i = 0; i < 4; i++ ){ if( dlg.m_prop2.m_skill[i] ){ strMsg += strSkill[i] + _T(","); } }
strMsg += _T("您的薪资范围选择是:") + dlg.m_prop3.m_money; MessageBox(strMsg, _T("最终选择")); } }
|
选择完之后就是这样的显示。
结语
主体对话框是RunningButtonDlg,通过按钮控件,显示出CMyPropSheet。然后写好的三个页与其关联。