Program examples compiled using Visual C++ 6.0 (MFC 6.0) compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this Tutorial are listed below:
Add the CDialog1 variables. Start ClassWizard and click on the Member Variables tab to view the Member Variables page. Enter the following member variables for each control listed.
Figure 16: Adding the CDialog1 variables. |
|
Program the short date time picker. In this example, we don't mind if the first date time picker starts with the current date, so we don't have any OnInitDialog() handling for this control. However, if we wanted to change the date, we would make a call to SetTime() for the control in OnInitDialog(). At runtime, when the user selects a new date in the first date and time picker, the companion static control should be automatically updated.
To achieve this, we need to use ClassWizard to add a handler for the DTN_DATETIMECHANGE message. Start ClassWizard (or CTRL-W) and choose IDC_DATETIMEPICKER1 from the Object IDs list and DTN_DATETIMECHANGE from the Messages list. Accept the default message name and click OK. Repeat this step for each of the other three IDC_DATETIMEPICKER IDs. Your ClassWizard should look like the illustration here.
Figure 17: Adding a handler for the DTN_DATETIMECHANGE message.
Next add the following code to the handler for Datetimepicker1 created by ClassWizard:
void CDialog1::OnDatetimechangeDatetimepicker1(NMHDR* pNMHDR, LRESULT* pResult)
{
CTime ct;
m_MonthCal1.GetTime(ct);
m_strDate1.Format(_T("%02d/%02d/%2d"), ct.GetMonth(),ct.GetDay(),ct.GetYear());
UpdateData(FALSE);
*pResult = 0;
}
Listing 1.
This code uses the m_MonthCal1 data member that maps to the first date time picker to retrieve the time into the CTime object variable ct. It then calls the CString::Format member function to set the companion static string. Finally the call to UpdateData(FALSE) triggers MFC's DDX and causes the static to be automatically updated to m_strDate1.
Program the long date time picker. Now we need to provide a similar handler for the second date time picker.
void CDialog1::OnDatetimechangeDatetimepicker2(NMHDR* pNMHDR, LRESULT* pResult)
{
CTime ct;
m_MonthCal2.GetTime(ct);
m_strDate2.Format(_T("%02d/%02d/%2d"), ct.GetMonth(),ct.GetDay(),ct.GetYear());
UpdateData(FALSE);
*pResult = 0;
}
Listing 2.
Program the third date time picker. The third date time picker needs a similar handler, but since we set the Show None style in the dialog properties, it is possible for the user to specify a NULL date by checking the inline check box. Instead of blindly calling GetTime(), we have to check the return value. If the return value of the GetTime() call is nonzero, the user has selected a NULL date. If the return value is zero, a valid date has been selected. As in the previous two handlers, when a CTime object is returned, it is converted into a string and automatically displayed in the companion static control.
void CDialog1::OnDatetimechangeDatetimepicker3(NMHDR* pNMHDR, LRESULT* pResult)
{
//NOTE: this one can be null!
CTime ct;
int nRetVal = m_MonthCal3.GetTime(ct);
if (nRetVal) //If not zero, it's null; and if it is,
// do the right thing.
{
m_strDate3 = "NO DATE SPECIFIED!!";
}
else
{
m_strDate3.Format(_T("%02d/%02d/%2d"),ct.GetMonth(),ct.GetDay(),ct.GetYear());
}
UpdateData(FALSE);
*pResult = 0;
}
Listing 3.
Program the time picker. The time picker needs a similar handler, but this time the format displays hours/minutes/seconds instead of months/days/years:
void CDialog1::OnDatetimechangeDatetimepicker4(NMHDR* pNMHDR, LRESULT* pResult)
{
CTime ct;
m_MonthCal4.GetTime(ct);
m_strDate4.Format(_T("%02d:%02d:%2d"), ct.GetHour(), ct.GetMinute(), ct.GetSecond());
UpdateData(FALSE);
*pResult = 0;
}
Listing 4.
Program the Month Selector. You might think that the month selector handler is similar to the date time picker's handler, but they are actually somewhat different. First of all, the message you need to handle for detecting when the user has selected a new date is the MCN_SELCHANGE message. Select this message in the ClassWizard, as shown here.
Figure 18: Adding message handler for IDC_MONTHCALENDAR1 ID.
In addition to the different message handler, this control uses GetCurSel() as the date time picker instead of GetTime(). The code below shows the MCN_SELCHANGE handler for the month calendar control.
void CDialog1::OnSelchangeMonthcalendar1(NMHDR* pNMHDR, LRESULT* pResult)
{
CTime ct;
m_MonthCal5.GetCurSel(ct);
m_strDate5.Format(_T("%02d/%02d/%2d"), ct.GetMonth(),ct.GetDay(),ct.GetYear());
UpdateData(FALSE);
*pResult = 0;
}
Listing 5.
Program the IP control. First we need to make sure the control is initialized. In this example, we initialize the control to 0 by giving it a 0 DWORD value. If you do not initialize the control, each segment will be blank. To initialize the control, add this call to the CDialog1::OnInitDialog function:
m_ptrIPCtrl.SetAddress(0L);
Listing 6.
Now we need to add a handler to update the companion static control whenever the IP address control changes. First we need to add a handler for the IPN_FIELDCHANGED notification message using ClassWizard, as shown here.
Figure 19: Adding a handler for the IPN_FIELDCHANGED notification message using ClassWizard.
Next we need to implement the handler as follows:
void CDialog1::OnFieldchangedIpaddress1(NMHDR* pNMHDR, LRESULT* pResult)
{
DWORD dwIPAddress;
m_ptrIPCtrl.GetAddress(dwIPAddress);
m_strIPValue.Format("%d.%d.%d.%d %x.%x.%x.%x",
HIBYTE(HIWORD(dwIPAddress)),
LOBYTE(HIWORD(dwIPAddress)),
HIBYTE(LOWORD(dwIPAddress)),
LOBYTE(LOWORD(dwIPAddress)),
HIBYTE(HIWORD(dwIPAddress)),
LOBYTE(HIWORD(dwIPAddress)),
HIBYTE(LOWORD(dwIPAddress)),
LOBYTE(LOWORD(dwIPAddress)));
UpdateData(FALSE);
*pResult = 0;
}
Listing 7.
The first call to CIPAddressCtrl::GetAddress retrieves the current IP address into the local dwIPAddress DWORD variable. Next we make a fairly complex call to CString::Format to deconstruct the DWORD into the various fields. This call uses the LOWORD macro to first get to the bottom word of the DWORD and the HIBYTE/LOBYTE macros to further deconstruct the fields in order from field 0 to field 3.
Add a handler for the first extended combo box. No special initialization is required for the extended combo box, but we do need to handle the CBN_SELCHANGE message. The following code shows the extended combo box handler. Can you spot the ways that this differs from a "normal" combo box control?
Figure 20: Adding a handler for the first extended combo box, IDC_COMBOBOXEX1.
void CDialog1::OnSelchangeComboboxex1()
{
COMBOBOXEXITEM cbi;
CString str ("dummy_string");
CComboBoxEx * pCombo = (CComboBoxEx *)GetDlgItem(IDC_COMBOBOXEX1);
int nSel = pCombo->GetCurSel();
cbi.iItem = nSel;
cbi.pszText = (LPTSTR)(LPCTSTR)str;
cbi.mask = CBEIF_TEXT;
cbi.cchTextMax = str.GetLength();
pCombo->GetItem(&cbi);
SetDlgItemText(IDC_STATIC7,str);
return;
}
Listing 8.
The first thing you probably noticed is the use of the COMBOBOXEXITEM structure for the extended combo box instead of the plain integers used for items in an older combo box. Once the handler retrieves the item, it extracts the string and calls SetDlgItemText() to update the companion static control.
Add Images to the Items in the second extended combo box. The first extended combo box does not need any special programming. It is used to demonstrate how to implement a simple extended combo box very similar to the older, non-extended combo box. The second combo box requires a good bit of programming. First we created six bitmaps and eight icons that we need to add to the resources for the project, as shown in the following illustration.
Figure 21: A complete bitmap and icon set that you have to create.
Of course, you are free to use any bitmaps and icons.
Figure 22: Inserting new resource, a bitmap.
Figure 23: Selecting the bitmap resource. |
Figure 24: Inserting a new icon.
Figure 25: Editing the icon and modifying the properties.
Figure 26: A completed set of the bitmaps and icons for MYMFC25A project.
There are two ways to add our graphics to an extended combo box. The first method is to attach images to existing combo box items. Remember that we used the dialog editor to add the Doremon, Tweety, Mack, etc. items to the combo box. The second method is to add new items and specify their corresponding images at the time of addition.
Before we start adding graphics to the extended combo box, let's create a public CImageList data member in the CDialog1 class named m_imageList. Be sure you add the data member to the header file (Dialog1.h) for the class.
Figure 27: Adding a public CImageList data member to the CDialog1 class.
Figure 28: Entering the variable type and name.
Now we can add some of the bitmap images to the image list and then "attach" the images to the three items already in the extended combo box. Add the following code to your CDialog1's OnInitDialog() method to achieve this:
//Initialize the IDC_COMBOBOXEX2
CComboBoxEx* pCombo = (CComboBoxEx*) GetDlgItem(IDC_COMBOBOXEX2);
//First let's add images to the items there.
//We have six images in bitmaps to match to our strings:
//CImageList * pImageList = new CImageList();
m_imageList.Create(32,16,ILC_MASK,12,4);
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BMBIRD);
m_imageList.Add(&bitmap, (COLORREF)0xFFFFFF);
bitmap.DeleteObject();
bitmap.LoadBitmap(IDB_BMBIRDSELECTED);
m_imageList.Add(&bitmap, (COLORREF)0xFFFFFF);
bitmap.DeleteObject();
bitmap.LoadBitmap(IDB_BMDOG);
m_imageList.Add(&bitmap, (COLORREF)0xFFFFFF);
bitmap.DeleteObject();
bitmap.LoadBitmap(IDB_BMDOGSELECTED);
m_imageList.Add(&bitmap, (COLORREF)0xFFFFFF);
bitmap.DeleteObject();
bitmap.LoadBitmap(IDB_BMFISH);
m_imageList.Add(&bitmap, (COLORREF)0xFFFFFF);
bitmap.DeleteObject();
bitmap.LoadBitmap(IDB_BMFISHSELECTED);
m_imageList.Add(&bitmap, (COLORREF)0xFFFFFF);
bitmap.DeleteObject();
//Set the imagelist
pCombo->SetImageList(&m_imageList);
//Now attach the images to the items in the list.
COMBOBOXEXITEM cbi;
cbi.mask = CBEIF_IMAGE|CBEIF_SELECTEDIMAGE|CBEIF_INDENT;
CString strTemp;
int nBitmapCount = 0;
for (int nCount = 0;nCount < 3;nCount++)
{
cbi.iItem = nCount;
cbi.pszText = (LPTSTR)(LPCTSTR)strTemp;
cbi.cchTextMax = 256;
pCombo->GetItem(&cbi);
cbi.iImage = nBitmapCount++;
cbi.iSelectedImage = nBitmapCount++;
cbi.iIndent = (nCount & 0x03);
pCombo->SetItem(&cbi);
}
Listing 9.
First the extended combo box initialization code creates a pointer to the control using GetDlgItem(). Next it calls Create() to create memory for the images to be added and to initialize the image list. The next series of calls loads each bitmap, adds them to the image list, and then deletes the resource allocated in the load.
CComboBoxEx::SetImageList is called to associate the m_imageList with the extended combo box. Next a COMBOBOXEXITEM structure is initialized with a mask, and then the for loop iterates from 0 through 2, setting the selected and unselected images with each pass through the loop. The variable nBitmapCount increments through the image list to ensure that the correct image ID is put into the COMBOBOXEXITEM structure. The for loop makes a call to CComboBoxEx::GetItem to retrieve the COMBOBOXEXITEM structure for each item in the extended combo box. Then the loop sets up the images for the list item and finally calls CComboBoxEx::SetItem to put the modified COMBOBOXEXITEM structure back into the extended combo box and complete the association of images with the existing items in the list.
Add Items to the Extended Combobox. The other technique available for putting images into an extended combo box is to add them dynamically, as shown in the code added to OnInitDialog() below:
HICON hIcon[8];
int n;
//Now let's insert some color icons
hIcon[0] = AfxGetApp()->LoadIcon(IDI_WHITE);
hIcon[1] = AfxGetApp()->LoadIcon(IDI_BLACK);
hIcon[2] = AfxGetApp()->LoadIcon(IDI_RED);
hIcon[3] = AfxGetApp()->LoadIcon(IDI_BLUE);
hIcon[4] = AfxGetApp()->LoadIcon(IDI_YELLOW);
hIcon[5] = AfxGetApp()->LoadIcon(IDI_CYAN);
hIcon[6] = AfxGetApp()->LoadIcon(IDI_PURPLE);
hIcon[7] = AfxGetApp()->LoadIcon(IDI_GREEN);
for (n = 0; n < 8; n++) {
m_imageList.Add(hIcon[n]);
}
static char* color[] = {"white", "black", "red",
"blue", "yellow", "cyan",
"purple", "green"};
cbi.mask = CBEIF_IMAGE|CBEIF_TEXT|CBEIF_OVERLAY|CBEIF_SELECTEDIMAGE;
for (n = 0; n < 8; n++) {
cbi.iItem = n;
cbi.pszText = color[n];
cbi.iImage = n+6; // 6 is the offset into the image list from
cbi.iSelectedImage = n+6; // the first six items we added...
cbi.iOverlay = n+6;
int nItem = pCombo->InsertItem(&cbi);
ASSERT(nItem == n);
}
-------------------------------------------------------------------------------------------------------
Listing 10.
The for loop fills out the COMBOBOXEXITEM structure and then calls CComboBoxEx::InsertItem with each item to add it to the list.
Add a handler for the second extended combo box. The second extended combo box handler is essentially the same as the first:
Figure 29: Adding a handler for the second extended combo box, IDC_COMBOBOXEX2.
void CDialog1::OnSelchangeComboboxex2()
{
COMBOBOXEXITEM cbi;
CString str ("dummy_string");
CComboBoxEx * pCombo = (CComboBoxEx *)GetDlgItem(IDC_COMBOBOXEX2);
int nSel = pCombo->GetCurSel();
cbi.iItem = nSel;
cbi.pszText = (LPTSTR)(LPCTSTR)str;
cbi.mask = CBEIF_TEXT;
cbi.cchTextMax = str.GetLength();
pCombo->GetItem(&cbi);
SetDlgItemText(IDC_STATIC8, str);
return;
}
Listing 11.
Connect the view and the dialog. Add code to the virtual OnDraw() function in mymfc25AView.cpp. The following code replaces the previous code:
void CMymfc25AView::OnDraw(CDC* pDC)
{
pDC->TextOut(30, 30, "Press the left mouse button here.");
}
Listing 12.
Use ClassWizard to add the OnLButtonDown() member function to the CMymfc25AView class. Edit the AppWizard-generated code as follows:
Figure 30: Adding the OnLButtonDown() member function to the CMymfc25AView class to handle the left mouse click.
void CMymfc25AView::OnLButtonDown(UINT nFlags, CPoint point)
{
CDialog1 dlg;
dlg.DoModal();
}
Listing 13.
Add a statement to include Dialog1.h in file mymfc25AView.cpp.
Listing 14.
Compile and run the program. Now you can experiment with the various IE4 common controls to see how they work and how you can apply them in your own applications.
Figure 31: MYMFC25A program output.
Figure 32: MYMFC25A program output, full of Internet Explorer 4 common controls.
Further reading and digging:
MSDN What's New (MFC Feature Pack) - feature pack.
DCOM at MSDN.
COM+ at MSDN.
COM at MSDN.
Unicode and Multi-byte character set: Story and program examples.