Author : Unknown
Page : << Previous 11 Next >>
sub-items. The following is the portion of function CCCtlDlg::OnInitDialog() that demonstrates creating one sub-item:
(Code omitted)
Function CListCtrl::InsertItem(...) is called to add a list item and set its first sub-item. The rest sub-items should be set by calling function CListCtrl::SetItem(...). For these sub-items, we don't need to set image again, so LVIF_IMAGE flag is not applied when function CListCtrl::SetItem(...) is called.
Changing List Style Dynamically
The style of the list control can be set in property sheet "List control properties" before the application is compiled(see Figure 14). But, sometimes we may want to provide the user with the power of changing this style dynamically. When the program is running, we can call API function ::SetWindwoLong(...) to change the application's style. For list control, we can choose from one of the following styles: LVS_ICON, LVS_SMALLICON, LVS_LIST and LVS_REPORT.
In the sample, four radio buttons are added to the dialog template for selecting different styles. Their IDs are IDC_RADIO_ICON, IDC_RADIO_SMALLICON, IDC_RADIO_LIST and IDC_RADIO_REPORT respectively. We need to handle BN_CLICKED message for the four radio buttons in order to respond to mouse events. These message handlers are added through using Class Wizard. Within the member functions, the style of the list control is changed according to which radio button is being clicked. The following is one of the message handlers that sets the style of the list control to "Normal Icon":
(Code omitted)
First, the list control's old style is retrieved by calling function ::GetWindowLong(...), and is bit-wisely ANDed with LVS_TYPEMASK, which will turn off all the style bits. Then style LVS_ICON is added to the window style (through bit-wise ORing), and function ::SetWindowLong(...) is called to update the new style. Both function ::GetWindowLong(...) and ::SetWindowLong(...) require a window handle, it could be obtained by calling function CWnd:: GetSafeHwnd().
The list control and tree control can also be implemented in SDI and MDI applications. In this case, we need to use classes derived from CListView or CTreeView. Although the creating procedure is a little different from that of a dialog box, the properties of the controls are exactly the same for two different types of applications. We will further explore list control and tree control in chapter 1
16 Tab Control
In the previous sample, we used radio buttons to let the user set the style of list control dynamically. An alternate way of doing this is to use tab control, which is widely used in various types of applications. Usually a tab control is used together with dialog box to implement property sheets, which can let the user easily switch among different property pages. This topic will be discussed in a chapter 7. Here, we will discuss some basics on how to implement tab control and handle its messages.
Using Tab Control
In MFC, tab control can be implemented by using class CTabCtrl. A tab control can be associated with an image list, so we can display both image and text on each tab. The steps of using a tab control is very similar to that of list control and tree control: first we need to add tab control resource to the dialog template; then in the dialog's initialization stage, we need to create the image list, select it into the tab control, and initialize the tab control. The function that can be used to assign image list to a tab control is CTabCtrl::SetImageList(...), which has the following format:
CImageList *CTabCtrl::SetImageList(CImageList *pImageList);
The function that can be used to add an item to the tab control is CTabCtrl::InsertItem(...):
BOOL CTabCtrl::InsertItem(int nItem, TC_ITEM *pTabCtrlItem);
The first parameter of this function is the index of the tab (zero based), and the second parameter is a pointer to TC_ITEM type object. Before calling this function, we need to stuff structure TC_ITEM with tab's information:
typedef struct _TC_ITEM {
UINT mask;
UINT lpReserved1;
UINT lpReserved2;
LPSTR pszText;
int cchTextMax;
int iImage;
LPARAM lParam;
} TC_ITEM;
We need to use three members of this structure in order to create a tab with both text and image: mask, pszText and iImage. Member mask indicates which of the other members of this structure contains valid data; member pszText is a pointer to string text; and iImage is an image index to the associated image list. We see that using this structure is very similar to that of TV_ITEM and LV_ITEM.
To respond to tab control's activities, we need to add message handlers for it. The most commonly used messages of tab control are TCN_SELCHANGE and TCN_SELCHANGING, which indicate that the current selection has changed or the current selection is about to change respectively.
Sample 16\CCtl demonstrates how to use tab control, it is based on sample 15\CCtl. In this sample, four radio buttons are replaced by a tab control IDC_TAB (see Figure 14). Also, message handlers of radio buttons are removed. In order to access the tab control, a CTabCtrl type control variable m_tabCtrl is added to class CCCtlDlg through using Class Wizard. Beside this, four bitmap resources IDB_BITMAP_ICON, IDB_BITMAP_SMALLICON, IDB_BITMAP_LIST and IDB_BITMAP_REPORT are added to the application to create image list for tab control.
In function CCCtlDlg::OnInitDialog(), first the image list is created and assigned to the tab control. Next, four items are added to the tab control:
(Code omitted)
Macro TAB_BMP_WIDTH and TAB_BMP_HEIGHT are defined as the width and height of the bitmaps. In function CCCtlDlg::Destroy(), the following statements are added to delete the tab items and the image list used by the tab control:
(Code omitted)
Handling Tab Control Message
We trap message TCN_SELCHANGE to respond to the changes on the tab control. After receiving this message, we call function CTabCtrl::GetCurSel() to obtain the newly selected item, then call function ::SetWindowLong(...) to set the style of the list control accordingly. In the sample, function CCCtlDlg::OnSelchangeTab(...) is added to class CCCtlDlg through using Class Wizard for handling this message. It is implemented as follows:
(Code omitted)
With the above implementation, we can change the list control's style dynamically through using the tab control.
17 Animate Control and Progress Control
Using Animate Control and Progress Control
Animate and progress controls are very useful, both of them can be implemented in a dialog box very easily. In MFC, the classes used to implement animate and progress controls are CAnimateCtrl and CProgressCtrl respectively.
Sample 17\CCtl demonstrates how to use two types of controls. It is a dialog-based application generated by Application Wizard.
Like any other common controls, the first step of using animate and progress controls is to add their resources to the dialog template. There are very few styles that can be customized, and the meanings of them are all self-explanatory. To access the controls, we can use Class Wizard to add member variables for them.
For animate control, the functions we need to call for implementing animation are CAnimateCtrl::Open(...) and CAnimateCtrl::Play(...). The first function lets us open an animation resource either from a file or from an AVI resource. The second function lets us play the loaded AVI data.
For progress control, we need to call function CProgressCtrl::SetRange(...) to set the upper and lower limits, call CProgressCtrl::SetStep(...) to specify the incremental step, and call CProgressCtrl:: StepIt() to advance the current position of progress bar. Each time we call this function, the progress bar will advance one step. In order to let the progress bar advance continuously, we need to link it to some events that happen all the time. In the sample, a timer is used to generate this type of events.
Timer
Timer is a very useful resource in Windows( operating system. Once we set the timer and specify the time out period, it will start to count down and send us a WM_TIMER message when time out happens. The timer can be set within any CWnd derived class by calling function CWnd::SetTimer(...). Timers with different IDs are independent upon one another, so we can set more than one timer to handle complex situation.
The following is the prototype of function CWnd::SetTimer(...):
UINT CWnd::SetTimer
(
UINT nIDEvent, UINT nElapse,
void(CALLBACK EXPORT *lpfnTimer)(HWND, UINT, UINT, DWORD)
);
The function has three parameters. Parameter nIDEvent is an event ID. This ID can be any integer, and we need to use different ID for different event in order to distinguish between them. Parameter nElapse specifies time out period, whose unit is millisecond. Parameter lpfnTimer is a pointer to a callback function that will be used to handle time out message. We can also pass NULL to this parameter and add WM_TIMER message handler to receive this message.
In the sample, the IDs of the animate control and progress control are IDC_ANIMATE and IDC_PROGRESS. Also, the variables used to access them are m_animateCtrl and m_progressCtrl respectively.
Custom Resource
The AVI data can be included in the application as a resource. However, Developer Studio does not support this kind of resource directly. So we have to treat it as a custom resource. We can create AVI resource from a "*.avi" file through following steps: 1) Execute Insert | Resource command, then click "Import" button from the "Insert resource" dialog box. 2) From the popped up "File open" dialog box, browse and select a "*.avi" file and open it (we can use "17\CCtl\search.avi" or any other "*.avi" file for this purpose). 3) When we are asked to provide the resource
Page : << Previous 11 Next >>