Create an MFC project and select a dialog box-based application. We found that the documentary application has only three classes:
Caboutdlg: similar to a single document, used to display help. In fact, this can be completely avoided.
Ctestapp: an essential class for an MFC application. theapp represents the application itself.
Ctestdlg: the main interface of the dialog box-based MFC application, derived from cdialog.
Let's first look at a simple problem: the creation of the escape button. It looks like an event: When you move the mouse over a button, it moves to another place, so you can never click it. But its implementation is actually like this: we have two buttons. Every time you move the mouse over the first button, it hides itself and calls the function to display the second button. Based on this idea, we will design it.
First, where can I capture the mouse-moving message? It must not be in the ctestdlg class. Otherwise, the button will be displayed or hidden in the dialog box. We can create a new class cnewbutton derived from cbutton, which is completed using classwizard, and then associate the button control with this new class. Right-click the two buttons and use the Class Wizard to add the variable m_btn1 and m_btn2 of the cnewbutton class. We need to include the following in the header file of the ctestdlg class: # include "newbutton. H ". Let cnewbutton capture and move the message. Add the message response function of wm_mousemove to this class. Call showwindow and select sw_show as the parameter to display a window. sw_hide hides a window. However, when we want to hide ourselves, we also need to display another window, so we need to add a member variable for our ctestdlg, which has a pointer to cnewbutton, it stores the address of another button. This initialization task is added in oninitdialog:
m_btn1.m_pBtn = &m_btn2;m_btn2.m_pBtn = &m_btn1;
Then our onmousemove is simple:
void CNewButton::OnMouseMove(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultShowWindow(SW_HIDE);m_pBtn->ShowWindow(SW_SHOW);CButton::OnMouseMove(nFlags, point);}
For the sake of beauty, we set one of the two buttons to invisible, and then it is more like what is going on.
The following describes how to generate an attribute form and create a wizard.
The following describes how to generate an attribute form:
Insert-> resource-> property page, insert three property pages, set their IDs to idd_prop1, idd_prop2, and idd_prop3 respectively, and set their tags to page1, page2, and page3.
Put a group box in page1: The group box is used to put the relevant content together to make it easy for users to use. change its title to "select your career :"; then, put three buttons in the group box and set them to "programmer", system engineer, and Project Manager respectively. Then, put a list box next to the group box, then place a static text box on it with the title changed to "select your work location ".
Place a group box in page2 and change the name to your hobbies. Set the four check boxes in the box, the name is changed to "football", "basketball", "Volleyball", and "swimming ".
Put a combo box in page3. There are three types of combos: simple, drop-down, and drop-down. Select the drop-down list. Then, put a static text box on it and change the name to "select your salary level ".
After three resources are available, you need to generate corresponding classes for them. view the corresponding classes and create a Class Wizard. Add new classes named cprop1, cprop2, and cprop3 respectively. Make sure that their IDs correspond to the three resources and set their base class to cpropertypage.
With these classes and resources, we can create an attribute form: first create a cpropsheet object, and then add the member variables m_prop1, m_prop2, and m_prop3 of the preceding three classes to it. Note: The corresponding header files must be included here. Then, call the addpage function in the cpropsheet constructor to add the three property pages to the Attribute Table.
Finally, we add a menu item to the menu and respond to the message for clicking this menu item in the View class.
void CPropView::OnPropertysheet() {// TODO: Add your command handler code hereCPropSheet propSheet("");propSheet.DoModal();}
After compilation and running, we found that the Chinese characters above are garbled characters. On the property page, we changed the language to China and changed the font to the Chinese font.
To sum up, the entire work is divided into the following steps:
1. Create a property page.
2. Associate the property page with the corresponding class.
3. Create an Attribute Table class, add variables related to the attribute page for the Attribute Table, and add the attribute page to the Attribute Table through addpage In the constructor.
4. Add a menu item. In the response message, call the domodal function of the Attribute Table to display the modal Attribute Table.
Create a wizard
The create wizard is similar to creating an attribute form, but before domodal, call the setwizardmode function, a member of cpropsheet.
After the call, we found that in the default form, the first page has the previous step and the last page has the next step, which is not expected, you can use the setwizardbuttons function to select what exists on each page. Through msdn, we can know that it is best to call this function in the onsetactive function of cpropertypage. Onsetactive is a virtual function. In our Derived classes cprop1, cprop2, and cprop3, We can overwrite them:
BOOL CProp1::OnSetActive() {// TODO: Add your specialized code here and/or call the base class((CPropertySheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT);return CPropertyPage::OnSetActive();}
Note: After obtaining base class pointers through getparent, convert them to the cpropertysheet * type.
Next, we hope that if you do not select one of the items in the wizard, you will not be able to proceed to the next step.
First, we need to associate these options with an object to record whether it is selected. Right-click a single sequence, select the create Class Wizard, and select the member variable. We find that the idnumber of the single sequence is idc_radio1, Which is because, for a single sequence, MFC adds a "group" flag to indicate that only one option can be selected from the single queue to the next single Queue (not included. We will select the group option of the first single queue and it will be OK. We can associate it with an int-type member variable m_occupation. We can see that in the constructor, It is initialized to-1, indicating that there is no selection. When the first option is selected, m_occupation is set to 0, and the second option is set to 1, and so on.
Therefore, when you click the "Next" button on the property page, you must first determine m_occupation. The "Next" operation is implemented by adding the onwizardnext virtual function to cprop1. The function of the derived class still calls the onwizardnext function of the base class. If this function returns 0, it will automatically go to the next page. If-1 is returned, it will stay on this page, so we can write:
Lresult cprop1: onwizardnext () {// todo: add your specialized code here and/or call the base class // This function must be used to obtain the value updatedata (); if (-1 = m_occupation) {MessageBox ("select a career! "); Return-1;} elsereturn cpropertypage: onwizardnext ();}
Next we will judge the content of the list box. First, we need to add several options for the list box:
Bool cprop1: oninitdialog () {cpropertypage: oninitdialog (); // todo: add extra initialization here (clistbox *) getdlgitem (idc_list1 )) -> addstring ("Beijing"); (clistbox *) getdlgitem (idc_list1)-> addstring ("Tianjin"); (clistbox *) getdlgitem (idc_list1 )) -> addstring ("Shanghai"); Return true; // return true unless you set the focus to a control // exception: OCX property pages shocould return false}
The class corresponding to the list box is clistbox, which adds options through its addstring function. Then make a judgment. Similarly, we need to associate it with the member variable m_workaddr of the cstring type:
If ("" = m_workaddr) {MessageBox ("select a work location! "); Return-1 ;}
Next we will process the second interface. We will add four member variables m_football, m_basketball, m_volleyball, and m_swim for the four check box buttons. In the constructor, they are all initialized to false, therefore, we need to determine whether one of them is true. If yes, we can proceed to the next step:
Lresult cprop2: onwizardnext () {// todo: add your specialized code here and/or call the base classupdatedata (); If (m_basketball | m_football | m_volleyball | m_swim) {return cpropertypage: onwizardnext ();} else {MessageBox ("select a hobby! "); Return-1 ;}}
Next we will process page 1. Similar to the list box on page 1, the class corresponding to the combo box is ccombobox. You can use the addstring function to add members to the drop-down list:
Bool cprop3: oninitdialog () {cpropertypage: oninitdialog (); // todo: add extra initialization here (ccombobox *) getdlgitem (idc_combo1 )) -> addstring ("less than 1000 yuan"); (ccombobox *) getdlgitem (idc_combo1)-> addstring ("1000 yuan to 2000"); (ccombobox *) getdlgitem (idc_combo1)-> addstring ("2000 yuan to 3000"); (ccombobox *) getdlgitem (idc_combo1)-> addstring ("more than 3000 yuan "); return true; // return true unless you set the focus to a control // exception: OCX property pages shoshould return false}
When running the program, we find that the display order is different from what we want. This is because the MFC comes with the sorting function. In the attribute-> style of this combo box, you can remove the category items.
In addition, we want the list box to have the default options, which can be implemented through setcursel.
((CComboBox*)GetDlgItem(IDC_COMBO1))->SetCurSel(0);
With the default options, we do not need to determine whether or not the user chooses.
Next, we will make a simple response for our options: When the click is complete, the selection result will be displayed in the View class. First, add the onwizardfinish virtual function with the response clicked in prop3, and then add a cstring member variable m_strsalary to carry the selected salary. Getcursel is used to obtain the selected option, and getlbtext is used to store the option content in m_strsalary:
BOOL CProp3::OnWizardFinish() {// TODO: Add your specialized code here and/or call the base classint index;index = ((CComboBox*)GetDlgItem(IDC_COMBO1))->GetCurSel();((CComboBox*)GetDlgItem(IDC_COMBO1))->GetLBText(index,m_strSalary);return CPropertyPage::OnWizardFinish();}
Next we will officially start our display work. Add variables in our view class to save the selected results:
int m_iOccupation;CString m_strWorkAddr;BOOL m_bLie[4];CString m_strSalary;
And initialize them in the constructor:
CCH_8_PROPView::CCH_8_PROPView(){// TODO: add construction code herem_iOccupation = -1;m_strWorkAddr = "";memset(m_bLike,0,sizeof(m_bLike));m_strSalary = "";}
With this data, if the user clicks "done", we should display the data. If it is "canceled", it will not be displayed. So how can we determine what users click? It is determined by the return value of the domodal function:
Void cch_8_propview: onpropertysheet () {// todo: add your command handler code herecpropsheet propsheet ("attribute form"); propsheet. setwizardmode (); If (id_wizfinish = propsheet. 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 [0] = propsheet. m_prop2.m_basketball; m_blike [0] = propsheet. m_prop2.m_volleyball; m_blike [0] = propsheet. m_prop2.m_swim; m_strsalary = propsheet. m_prop3.m_strsalary; invalidate ();}}
We store all the options in the wizard in the variables in the View class, and then call invalidate (); yes, the customer zone becomes invalid, causing re-painting.
Then we can display the information in the ondraw function:
Void cch_8_propview: ondraw (CDC * PDC) {cch_8_propdoc * pdoc = getdocument (); assert_valid (pdoc); // todo: Add draw code for native data herecstring strtmp; strtmp = "Your Career:"; Switch (m_ioccupation) {Case 0: strtmp + = "programmer"; break; Case 1: strtmp + = "system engineer"; break; case 2: strtmp + = "Project Manager"; break; default: break;} PDC-> textout (0, 0, strtmp); strtmp = "your location :"; strtmp + = m_strworkaddr; textmetric TM; PDC-> gettextmetrics (& TM); PDC-> textout (0, TM. tmheight, strtmp); strtmp = "Your hobbies:"; if (m_blike [0]) strtmp + = "soccer"; if (m_blike [1]) strtmp + = "basketball"; if (m_blike [2]) strtmp + = "Volleyball"; if (m_blike [3]) strtmp + = "swimming "; PDC-> textout (0, TM. tmheight * 2, strtmp); strtmp = "your salary level:"; strtmp + = m_strsalary; PDC-> textout (0, TM. tmheight * 3, strtmp );}
In this example, in order to be able to display in the next line without repeating the display, the system font we obtain uses its height information.