Collected
Add attribute page in the dialog box
Author: Huang chenliang
Download all source code in this article
When a dialog box-based program contains a considerable number of controls, you will surely think of using property pages to classify these controls. This article discusses several possible implementations of this method.
Solution 1
For an example of this solution, see section Property1 in the source code package file.
Place a Tab Control on the dialog box, and then place the required Control on the dialog box (in this example, two buttons are placed to try to display one in each label ). Then, use Class Wizard to create a Control variable for the Tab Control, which belongs to the CTabCtrl Class, and create corresponding Control classes for other controls. In the initial function of the Main Dialog Box, add the following code to CProperty1Dlg: OnInitDialog:
// In this example, two tags are inserted. In actual use, you can insert the required number of tags in a loop. After running, m_tab.InsertItem (0, _ T ("Tab1") is selected by default ")); m_tab.InsertItem (1, _ T ("Tab2"); // hide the control that is not the first tag, leaving only the control m_button2.ShowWindow (SW_HIDE) you want );
Use ClassWizard to process the TCN_SELCHANGE message of Tab Control. In the message processing function, CWnd: ShowWindow is used to display and hide corresponding controls.
Void CProperty1Dlg: OnSelchangeTab1 (NMHDR * pNMHDR, LRESULT * pResult) {// GetCurSel returns the index number of the selected tag (based on 0) int sel = upper (); switch (sel) {case 0: m_button1.ShowWindow (SW_SHOW); m_button2.ShowWindow (SW_HIDE); break; case 1: lower (SW_SHOW); m_button1.ShowWindow (SW_HIDE ); break;} * pResult = 0 ;}
After doing so, the controls on the interface will be displayed in different labels, but this solution also has many disadvantages.
All controls are still in the same dialog box. It is inconvenient to edit them using the dialog box editor.
In order to be able to classify display controls, you must use ClassWizard to create a control variable for each control so that the ShowWindow function of the CWnd base class of each control variable can be used to display and hide the control variables. Sometimes, to use the DDX and DDV mechanisms for data exchange, you also need to create some variables that store values, which makes the entire dialog box class very large and difficult to operate.
Of course, you can also use arrays to store those control variables or value variables, but this is not the best. Sometimes some irrelevant control variables are put into an array, accessing the control through an array index with no actual meaning can cause trouble in programming. It is best to classify all the controls and place them in the dialog box class. These dialogs appear as subdialogs in the main dialog box. Yes. Now let's look at solution 2.
Solution 2
For an example of this solution, see the Property2 section in the source code package file.
In this solution, I will use the ready-made CPropertySheet and CPropertyPage classes in MFC to distribute controls to various dialog box classes.
First, add two (or more) dialog box resources. Modify the resource attributes of each dialog box and change the Caption attribute of the dialog box to the text you want to display on the tab. Change the Style attribute of the dialog box to Child and the Border attribute to Thin. select only the Title Bar check box and remove other check boxes. Then you can add the controls to be separately displayed in these dialog boxes.
Create a dialog box class for the preceding dialog box resources, which is inherited from CPropertyPage. In this way, the sub-Dialog Box classes are ready, and the Main Dialog Box class can be directly used as the CPropertySheet class. Use the following code:
CPropertySheet sheet ("property page dialog box"); CPage1 page1; CPage2 page2; // Add sub-dialog box as a property page sheet. addPage (& page1); sheet. addPage (& page2); // generate a modal dialog box. You can also use the Create method to generate a non-modal dialog box (see MSDN for details. doModal ();
In this case, the dialog box is as follows:
However, someone may ask how to place other controls in the main dialog box? If you use CPropertySheet directly, it is not possible, but don't forget that we can inherit our own classes from the CPropertySheet class! Let's take a look at solution 3.
Solution 3
For an example of this solution, see the Property3 section in the source code package file.
The first step is to create the subdialog box classes to be displayed on the property page. The creation steps are the same as solution 2 and are inherited from CPropertyPage.
This time, we will inherit our class from the CPropertySheet class (assuming the class name is CMySheet ). We need to put a button control here. Now, add a member variable m_button of the CButton class to CMySheet.
In the OnInitDialog () function of the CMySheet class, write as follows:
BOOL bResult = CPropertySheet: oninitdiult (); // get the size of the property page CRect rectWnd; GetWindowRect (rectWnd); // adjust the width of the dialog box SetWindowPos (NULL, 0, 0, rectWnd. width () + 100, rectWnd. height (), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); CRect rectButton (rectWnd. width () + 25, 25, rectWnd. width () + 75, 75); // use a program to create a Button m_button.Create ("Button", BS_PUSHBUTTON, CRect (rectWnd. width (), 25, rectWnd. width () + 75, 50), this, 1); // display the button m_button.ShowWindow (SW_SHOW); CenterWindow (); return bResult;
The effect is as follows:
Solution 3 although you can add controls in the main dialog box, it is also troublesome. The added controls can only be on the right or bottom of the property page. It is cumbersome to use programs to generate controls, and the location and size are not easy to control. There are other ways to add a property page in the dialog box and add controls in the Main Dialog Box at will? There are still. Let's take a look at solution 4.
Solution 4
For an example of this solution, see the Property4 section in the source code package file.
This time we will not inherit our class from CPropertySheet, or use it directly. The subdialog classes on each property page are still required. The creation method is the same as the preceding two schemes.
First, create a dialog box-based project. You can add some required controls to edit an existing main dialog box, but you have to leave some space to place the property pages.
Add a member variable (m_sheet) of the CPropertySheet class to the Main Dialog Box class to represent the entire property page. Add instances of subdialog classes as member variables (m_page1, m_page2 ......).
In the OnInitDialog () function of the Main Dialog Box class, add:
// Add a label. The label name is determined by the title bar of each subdialog box m_sheet.AddPage (& m_page1); m_sheet.AddPage (& m_page2); // Create an attribute page m_sheet.Create (this, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT); RECT rect; m_sheet.GetWindowRect (& rect); int width = rect. right-rect. left; int height = rect. bottom-rect. top; // adjust the size and position of the property page m_sheet.SetWindowPos (NULL, 20, 50, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
The effect is as follows:
This solution allows you to add necessary controls in the main dialog box, and the controls on the property page are also scattered in various subdialog box classes, which is very convenient to use.
However, this also has some drawbacks: The Main Dialog Box cannot process the tag messages on the property page, that is, the Main Dialog Box cannot be notified when a tag is clicked. (I may be at a limited level. Theoretically, I should be able to solve this problem)
Solution 5
For an example of this solution, see section 5 of the source code package file.
This time, we still need to use Tab Control and inherit the class (CTabSheet) from the CTabCtrl Control class. (This method is from an article by CodeGuru. I will make some modifications to make it easier to use)
First, I will introduce how to use CTabSheet.
You must first create a subdialog box class. This subdialog box class should not be inherited from CPropertyPage, but directly from CDialog. In addition, the attributes of the sub-Dialog Box resources should be set to: Style, Border, and None.
In the main dialog box, add a Tab Control and adjust the position and size as appropriate. Use ClassWizard to create a CTabSheet Control variable for this Tab Control.
Add OnInitDialog () in the Main Dialog Box:
m_sheet.AddPage("tab1", &m_page1, IDD_DIALOG1);m_sheet.AddPage("tab2", &m_page2, IDD_DIALOG2);m_sheet.Show();
In this way, you can create a perfect property page on the dialog box. The effect is exactly the same.
Next I will talk about the details of the CTabSheet class.
CTabSheet is inherited from CTabCtrl and is used as the Control class for Tab Control. There is a member variable in the class to record the pointer CDialog * m_pPages [MAXPAGE] for each subdialog box; MAXPAGE is the maximum value of the labels that can be loaded by the class.
Class has an AddPage method, used to record the sub-Dialog Box pointer and the ID of the used dialog box resource.
BOOL CTabSheet: AddPage (LPCTSTR title, CDialog * pDialog, uint id) {if (MAXPAGE = m_nNumOfPages) return FALSE; // Save the total number of subdialogs m_nNumOfPages ++; // record the sub-Dialog Box pointer, resource ID, the text m_pPages [m_nNumOfPages-1] = pDialog; m_IDD [m_nNumOfPages-1] = ID; m_Title [m_nNumOfPages-1] = title; return TRUE ;}
After adding subdialogs to AddPage, you must call the Show method of CTabSheet to generate tags and subdialogs.
Void ctabsheet: Show () {// use cdialog: Create to create a subdialog box, and use ctabctrl: insertitem to add the corresponding label for (INT I = 0; I <m_nnumofpages; I ++) {m_ppages [I]-> Create (m_idd [I], this); insertitem (I, m_title [I]);} // because the first label is selected by default when the dialog box is displayed, the first subdialog box should be displayed. Other subdialogs hide m_ppages [0]-> showwindow (sw_show ); for (I = 1; I <m_nnumofpages; I ++) m_ppages [I]-> showwindow (sw_hide); setrect ();}
After the tag and subdialog box are generated, call ctabsheet: setrect to calculate and adjust the size of the attribute page.
Void ctabsheet: setrect () {crect tabrect, itemrect; int NX, NY, nxc, NYC; // The getclientrect (& tabrect); getitemrect (0, & itemrect); // calculate the position and size of each subdialog box relative to tab control. Nx = itemrect. left; ny = itemrect. bottom + 1; nxc = tabrect. right-itemRect.left-2; NYC = tabrect. bottom-nY-2; // use the calculated data to adjust the sub-Dialog Box m_ppages [0]-> setwindowpos (& wndtop, NX, NY, nxc, NYC, swp_showwindow ); for (INT ncount = 1; ncount <m_nnumofpages; ncount ++) m_ppages [ncount]-> setwindowpos (& wndtop, NX, NY, nxc, NYC, swp_hidewindow );}
After you click the tab bar, the corresponding subdialog box is displayed, and the displayed subdialog box is hidden. Therefore, ClassWizard is used to process WM_LBUTTONDOWN messages.
Void CTabSheet: OnLButtonDown (UINT nFlags, CPoint point) {CTabCtrl: OnLButtonDown (nFlags, point); // determine whether other labels if (m_nCurrentPage! = GetCurFocus () {// hide the original subdialog box m_pPages [m_nCurrentPage]-> ShowWindow (SW_HIDE); m_nCurrentPage = GetCurFocus (); // display the subdialog box m_pPages [m_nCurrentPage]-> ShowWindow (SW_SHOW);} corresponding to the current tag );}}
In this way, the CTabSheet class can be used to easily place its own property pages in the dialog box, and controls are scattered in each subdialog box class, in line with the idea of object encapsulation. In addition, you can use ClassWizard to easily generate a message ing to process the Tab Control message. For example, you can process the TCN_SELCHANGE message to perform some actions when the tag is switched.
This article uses five methods to add attribute pages in the dialog box. Of course, there should be other methods. If you have a limited level, don't forget to tell me if you have a better method.
Author Email: hcl-hcl@21cn.com