Changes to AppWizard, IE4 Controls, and a connection to DHTML make
this rev worth learning By Scot Wingo
You may already be enjoying the productivity gains from great new features in Microsoft Visual C++ 6.0 like the IDE, editor, and compiler. Now that youve had a chance to recompile your current projects with the latest rev of Visual C++, its time to look at whats new in the latest release of MFC, Version 6.0.
Fire It Up! |
The fastest way to discover whats new in MFC 6.0 is to fire up our old friend, AppWizard, and see whats changed since Version 5.0. Go ahead and start AppWizard by selecting File/New/MFC AppWizard (EXE).
Figure 1:New AppWizard functionality
The first difference youll notice occurs in step 1. Figure 1 shows a new option: Document/View architecture support? In previous versions, everything generated by AppWizard was automatically document/view-oriented, and you had to manually remove any document/view (and document template, etc.). Now if youre starting a project and dont care for document/view support, this option automatically omits document/view references from the generated code for you.
For this example, accept all of the defaults and go to step 4. Figure 2 shows step 4 of the AppWizard and another new option: How do you want your toolbars to look? with the Normal and Internet Explorer ReBars options. Choose Internet Explorer ReBars.
Figure 3: Project style option
At the top of Step 5, shown in Figure 3, youll get another new question: What style of project would you like? The options are MFC Standard or Windows Explorer. Choose the Windows Explorer option.
Finally, Step 6 includes a new but hidden feature. Can you find it? If you select a view, youll notice a new CView derivative: CHtmlView. Figure 4 shows where this new option lives.
Figure 4: CHtmlView
CHtmlView is fairly sophisticated, so well cover it in a separate section later. Accept the defaults in step 6 and compile and run the application. Figure 5 shows the application in action.
Figure 5: Working application
Notice that the application has a fancy new toolbar that slides and has grippers like the toolbar in Internet Explorer 4. Also notice that a splitter has automatically been created for us so that we can more easily create an Explorer-style application with a CTreeView in the left pane and a CListView in the right pane.
Lets learn more about the new ReBar control by exploring the code that AppWizard generated (so you can convert existing applications to use the new toolbar) and customize the default ReBar.
Anatomy of a ReBar |
In addition to the sliding and gripper functionality, the ReBar also allows you to provide many more internal control typessuch as drop-down menusthan are available in CToolBar. Before we explore these features lets look at the components of a ReBar.
Figure 6: ReBar elements
Figure 6 shows the various parts of a ReBar. Each internal toolbar in a ReBar is called a band. The raised edge where the user slides the band is called a gripper. Each band can also have a label as illustrated.
MFC 6.0 provides two new classes that facilitate working with ReBars:
![]() | CReBara high-level abstraction class that provides members for adding CToolBar and CDialogBar classes to ReBars as bands. CReBar also handles communication (such as message notifications) between the underlying control and the MFC framework. |
![]() | CReBarCtrla low-level wrapper class that wraps the IE ReBar control. This class provides numerous members for creating and manipulating ReBars, but doesnt provide the niceties found in CReBar. Most MFC applications use CReBar and call the member function GetReBarCtrl( ), which returns a CReBarCtrl pointer to gain access to the lower-level control on an as-needed basis. |
Working with CReBar |
If you open the MainFrm.h header file generated earlier by AppWizard, youll see the code below which declares the CReBar data member, m_ndReBar.
protected: // control bar embedded members CStatusBar m_wndStatusBar; CToolBar m_wndToolBar; CReBar m_wndReBar; CDialogBar m_wndDlgBar; |
In the MainFrm.cpp file, you can see the code that adds the toolbar and dialog bar to the CReBar:
if (!m_wndReBar.Create(this) || !m_wndReBar.AddBar(&m_wndToolBar) || !m_wndReBar.AddBar(&m_wndDlgBar)) { TRACE0("Failed to create rebar\n"); return -1; // fail to create } |
Lets customize the TODO: layout dialog bar band from the application we generated earlier with AppWizard.
First, open up the Visual C++ resource editor. Under the dialog heading youll find a dialog resource (for the dialog bar) with ID IDR_MAINFRAME, which contains TODO: layout dialog bar. Lets follow AppWizards suggestion and put some real controls into the dialog bar. First, delete the static control with the TODO text in it. Next, place a combo box in the dialog bar and enter some default data items: one, two, buckle, my, shoe! Now place a button and change the buttons text to Increment. Next, place a progress bar with the default properties and place another button with the text Decrement. When youre done laying out the dialog bar it should look similar to Figure 7.
Figure 7: Adding controls to the dialog bar
Before we can program the handlers for the Increment and Decrement buttons, we need to attach the dialog bar to a class using ClassWizard. While in the resource editor, bring up ClassWizard by double clicking on the Increment button. Choose Select an existing class. We choose this option because we want our dialog resource to be a band in the toolbar, not a separate dialog class. Choose CMainFrame from the list and select OK. ClassWizard prompts you with one last dialog. Select Yes and exit ClassWizard. You have successfully associated the IDR_MAINFRAME dialog bar with the CMainFrame class!
Finally, lets add some behavior to the dialog bar. Bring up the IDR_MAINFRAME dialog resource in the resource editor and double click on the Increment button. ClassWizard automatically creates an OnButton1( ) handler for youaccept the default name for this function. Enter this code for the OnButton1( ) function:
void CMainFrame::OnButton1() { CProgressCtrl * pProgress = (CProgressCtrl*)m_wndDlg Bar.GetDlgItem (IDC_PROGRESS1); pProgress->StepIt(); } |
The OnButton1( ) handler first gets a pointer to the progress control and then calls StepIt( ) to increment the progress control.
Now we need to add similar code to the decrement handler. Double click on the Decrement button in the resource editor, and ClassWizard will automatically create an OnButton2( ) handler. Add the following code to the OnButton2( ) member function:
void CMainFrame::OnButton2() { CProgressCtrl * pProgress = (CProgressCtrl*)m_wndDlgBar.GetDlgItem (IDC_PROGRESS1); int nCurrentPos = pProgress->GetPos(); pProgress->SetPos(nCurrentPos-10); } |
Figure 8: Application results
Now youre ready to compile and run the application. Figure 8 shows the results. This example is just the tip of the ReBar functionality iceberg, but it should give you an idea of how to get started and what its like to work with the new class. The Visual C++ on-line documentation is a great place to learn more about ReBars capabilities.
Actually, the ReBar is one of several new controls that are part of the Internet Explorer SDK now supported in MFC 6.0. Lets take a look at some of the other new controls that are supported.
IE 4 Controls |
When Microsoft released Internet Explorer 4, they included a new and improved version of the COMCTL32.DLL, which houses the Windows Common Controls. Because this update to the common controls wasnt part of an operating system release, Microsoft calls the update the Internet Explorer 4 Common Controls. It updates all of the existing controls and adds a variety of advanced new controls. Visual C++ 6.0 and MFC 6.0 include a great deal of support for these new controls.
Figure 9 shows a dialog with each of the new IE4 controls. You can refer to it as you read the descriptions of the controls that follow.
Figure 9: New IE4 controls
Date and Time Picker |
Before the date and time picker was provided with the IE4 controls, to enter a date, you had to use a third-party control, or subclass an MFC edit control to do significant data validation to ensure the entered date was valid. Fortunately, the new date and time picker provides an advanced control that prompts the user for a date or time while offering the developer a wide variety of styles and options. For example, dates can be displayed in short (8/14/68) or long (August 14, 1968) formats. A time mode lets the user enter a time using the familiar hour:minute:second AM/PM format.
The control also lets you decide if you want the user to select the date via in-place editing, a pop-down calendar, or a spinner. A variety of selection options are available, including single and multi (a range of dates) selections and the ability to turn on and off the red-ink circling of the current date. The control even has a mode that lets the user select no date by checking a check box. In Figure 9, the first four controls on the left illustrate the variety of configurations available with this control.
The new MFC 6.0 CDateTimeCtrl class provides the MFC interface to the IE4 date and time picker common control. This class offers a variety of notifications that enhance the programmability of the control. CDateTimeCtrl provides member functions for dealing with either CTime or COleDateTime time structures.
You set the date and time in a CDateTimeCtrl using the SetTime( ) member function and retrieve the date and time via the GetTime( ) function. You can create custom formats using the SetFormat( ) member function and change a variety of other configurations using the CDateTimeCtrl interface.
Month Calendar |
The large display at the bottom left of Figure 9 is a month calendar. Like the date and time picker, the month calendar lets the user choose a date; but the month calendar can also be used to implement a small Personal Information Manager (PIM) in your applications. You can use the month calendar to show from one to 12 months. Figure 9 uses the month calendar to show only two months.
The month calendar supports single or multiple selection and allows you to display a variety of different options such as numbered months and circled days. Notifications for the control let you specify which dates are bold. Its up to you to decide what this represents. For example, you could use the bold feature to indicate holidays, appointments, or invalid dates. The MFC 6.0 CMonthCalCtrl class provides the implementation of this control.
To initialize CMonthCal-Ctrl, you can call the SetToday() member function. CMonthCalCtrl provides members that deal with both CTime and COleDateTime.
Internet Protocol Address Control |
If you write an application that uses any form of Internet or TCP/IP functionality, you may need to prompt the user for an Internet Protocol (IP) address. The IE4 Common Controls include an IP address control as shown in the top right of Figure 9. In addition to allowing the user to enter a four-byte IP address, this control performs automatic validation of the entered IP address. CIPAddressCtrl provides MFC support for the IP address control.
Figure 10: IP address
An IP address consists of four fields as shown in Figure 10. The fields are numbered from left to right. To initialize an IP address control, call the SetAddress( ) member function in your OnInitDialog( ) function. SetAddress( ) takes a DWORD, with each byte in the DWORD representing one of the fields. In your message handlers, you can call the GetAddress( ) member function to retrieve a DWORD or a series of bytes to retrieve the various values of the four IP address fields.
Extended Combo Box |
The old fashioned combo box was developed in the early days of Windows, and its age and inflexible design have been the source of a great deal of developer confusion. With the IE4 controls, Microsoft released a much more flexible version of the combo box, called the extended combo box.
The extended combo box gives you much simpler access and control over the edit control portion of the combo box. In addition, the extended combo box lets you attach an image list to the items in the combo box so you can easily display graphics in it. (Remember the old days when you had to use owner-drawn combo boxes?) Each item in the extended combo box can be associated with a selected image, an unselected image, and an overlay image. These three images can be used to provide a variety of graphical displays in the combo box. The bottom two combo boxes in Figure 9 are both extended combo boxes. The MFC CComboBoxEx class provides comprehensive extended combo box support.
CComboBoxEx can be attached to a CImageList that will automatically display graphics next to the text in the extended combo box. If youre already familiar with CComboBox, CComboBoxEx may cause some confusion; instead of containing strings, the extended combo box contains items of type COMBOBOXEXITEM. COMBOBOXEXITEM is a structure that consists of the following fields:
![]() | UINT maskA set of bit flags that specify which operations are to be performed using the structure. For example, set the CBEIF_IMAGE flag if the iImage field is to be set or retrieved in an operation. |
![]() | int iItemExtended combo box item number. Like the older style combo box, the extended combo box uses zero-based indexing. |
![]() | LPTSTR pszTextText of the item. |
![]() | int cchTextMaxLength of the buffer available in pszText. |
![]() | int iImageZero-based index into an associated image list. |
![]() | int iSelectedImageIndex of the image in the image list to be used to represent the selected state. |
![]() | int iOverlayIndex of the image in the image list to be used to overlay the current image. |
![]() | int iIndentNumber of 10-pixel indentation spaces. |
![]() | LPARAM lParam32-bit parameter for the item. |
See Bill Wagners article, Build a Browser in an Afternoon Using Microsofts Web Browser at www.vcdj.com/vcdj/jul98 /browser1.asp for more more information.
The last and perhaps biggest new feature in MFC 6.0 is support for Dynamic HTML in the CHTMLView class.
DHTML Support |
Dynamic HTML (DHTML) is a new and exciting feature introduced as part of IE4. It provides serious benefits that could ultimately change the way we think about developing Windows applications. Whats the buzz about?
It all starts with the IE HTML display engine, sometimes called Trident in Microsoft literature. As part of the design of IE4, Microsoft made Trident its own COM component, exposing many of its internal objects used for displaying HTML pages in IE. This feature allows you to traverse the portions of an HTML page in script or code as if the HTML page was a data structure. Gone are the days of having to parse HTML or write grotesque CGI scripts to get to data in a form. The real power in DHTML doesnt lie in the ability to access the HTML objects, but to actually change and manipulate the HTML page on-the-flythus, the name Dynamic HTML.
Once you understand the concept of DHTML, a million possible applications come to mind. For the Webmaster, this means that much of the logic that manipulates a page can live in scripts that are downloaded to the client. For the C++ developer, it means you can embed DHTML in your applications and use it as an embedded Web client or as a super-flexible, dynamic form that your application can change on-the-fly. For an example of how to leverage Web views in your applications, try some of the new Internet-enabled applications like Quicken 99 or Microsoft Money 99.
DHTML is so powerful and extensive that it would take a separate book (like Inside Dynamic HTML by Scott Isaacs) to fill you in on all of the copious details. For example, to really leverage DHTML, you need to understand the many possible elements of an HTML page, such as forms, lists, and stylesheets. Instead of covering all of the aspects of DHTML, Ill briefly introduce you to the DHTML object model and show you how to work with it using MFC. This is all made possible by the excellent DHTML support introduced in Visual C++ 6.0.
The DHTML Object Model |
If youve been heads-down on a Visual C++ project and havent had time to peek at HTML, its an ASCII mark-up language format. Heres a very basic look at a simplistic HTML page:
<html> <head> <title> This is an example of a very basic HTML page! </title> </head> <body> <h1>This is some text with H1! </h1> <h3> This is some text with H3! </h3> </body> </html> |
This basic HTML document is composed of several elements. The head (or header) contains the title: This is an example of a very basic HTML page! Next, the body of the document contains two elements. The first element has a style of heading 1 (h1) and reads:
This is some text with H1! The last element includes text with style heading 3 (h3) that reads: This is some text with H3!
Figure 11: DHTML object model hierarchy
Graphic from Inside Dynamic HTML by Scott Isaacs. Reproduced by permission of Microsoft
Press. All rights reserved.
When IE loads this HTML page, it creates an internal representation that you can traverse, read, and manipulate through the DHTML object model. Figure 11 shows the basic hierarchy of the DHTML object model.
At the root of the object model is the window object. This object can be used from a script to do something like pop-up a dialog box. Heres an example of some script that accesses the window object:
<SCRIPT LANGUAGE="JavaScript"> function about() { window.showModalDialog("about.htm","", "dialogWidth:25em;dialogHeight13em") } </SCRIPT> |
When the about script is called, it in turn calls the showModalDialog( ) function in the window DHTML object to display a dialog. This example also illustrates how scripts access the object modelthrough globally accessible objects that map directly to the corresponding object in the DHTML object model.
The window object has several sub objects that further allow you to manipulate portions of IE4. The document object is what youll spend most of your time on when writing DHTML code, because it gives you programmatic access to the various elements of the HTML document currently loaded. The following script shows how to create basic dynamic content that changes the document object:
<HTML> <HEAD> <TITLE>Welcome!</TITLE> <SCRIPT LANGUAGE="JScript"> function changeMe() { document.all.MyHeading.outerHTML = "<H1 ID=MyHeading>Dynamic HTML is magic!</H1>"; document.all.MyHeading.style.color = "green"; document.all.MyText.innerText = "Presto Change-o! "; document.all.MyText.align = "center"; document.body.insertAdjacentHTML("BeforeEnd", "<P ALIGN=\"center\">Open Sesame!</P>"); } </SCRIPT> <BODY onclick="changeMe()"> <H3 ID=MyHeading> Dynamic HTML demo!</H3> <P ID=MyText>Click anywhere to see the power of DHTML!</P> </BODY> </HTML> |
This script changes the MyHeading and MyText objects in the HTML documents on-the-fly. Not only does it change the text, but it also changes attributes of the elements such as the color and alignment. This script is included with this article on www.vcdj.com.
Before we further decompose the DHTML object model, you need to understand the DHTML concept of a collection. Collections in DHTML are logically equivalent to C++ data structures such as linked lists. In fact, access to the DHTML object model is largely performed by iterating through collections searching for a particular HTML element and then potentially iterating through another sub-collection to get to yet another element. Elements contain several methods such as contains and length, which you use to traverse through the elements.
For example, one of the sub-elements of the document object is a collection called all that contains all of the documents elements. In fact, most of the sub-objects of the document object are collections. The following script shows how to iterate through the all collection and lists the various items of a document.
<HTML> <HEAD><TITLE>Iterating through the all collection.</TITLE> <SCRIPT LANGUAGE="JScript"> function listAllElements() { var tag_names = ""; for (i=0; i<document.all.length; i++) tag_names = tag_names + document.all(i).tagName + " "; alert("This document contains: " + tag_names); } </SCRIPT> </HEAD> <BODY onload="listAllElements()"> <H1>DHTML Rocks!</H1> <P>This document is <B>very</B> short. </BODY> </HTML> |
Notice how easy it is to retrieve items with script (using parentheses similar to how we access an array in C++)? Also notice that each element in an HTML document has properties such as tagName that allow you to search programmatically for various elements. For example, if you wanted to write a script that filtered out all bold items, you would scan the all collection for an element with tagName B.
Now that weve covered the basics of the DHTML object model and how to access them through scripts from the Web masters perspective, lets look at how MFC 6.0 lets us work with DHTML from an application developers perspective.
MFC 6.0 and the DHTML Connection |
MFC 6.0s CHTMLView gives you complete access to the DHTML object model. However, access to the object model from languages like C++ is done through OLE Automation (IDispatch) and in many cases isnt as cut-and-dried as some of the scripts we looked at earlier. The DHTML object model gets exposed through a set of COM objects with the prefix IHTML (as in IHTMLDoc-ument, IHTMLWindow, IHTMLElement, and IHTMLBody-Element). In C++, once youve obtained the document interface, you can use any of the IHTMLDocument2 interfaces to obtain or modify the documents properties.
You can access the all collection by calling the IHTMLDoc-ument2::get_all( ) method. This method returns an IHTML-ElementCollection collection interface that contains all the elements in the document. You can then iterate through the collection using the IHTMLElementCollection::item( ) method (similar to the parentheses in the scripts above). The IHTMLElementCollection::item( ) method supplies you with an IDispatch pointer on which you can call QueryInterface, requesting the IID_IHTMLElement interface. This gives you an IHTMLElement interface pointer to get or set information for the HTML element.
Most elements also provide a specific interface for working with that element type. These element-specific interface names take the format of IHTMLXXXXElement, where XXXX is the name of the element (as in IHTMLBodyElement). You must call QueryInterface on the IHTMLElement object to request the element-specific interface you need. If this sounds confusing, it can be! But dont worry, well go through an example of how to use DHTML with MFC.
Where the Connection Begins |
MFCs support for DHTML starts with a new CView derivative, CHtmlView, allowing you to embed an HTML view inside of frame windows or splitter windows. With some DHTML work, CHtmlView can act as a dynamic form. Lets use it to generate a simple application and add some DHTML manipulation code.
First, create a simple MDI application with a CHtmlView as the view. In Visual C++, select File/New/Projects and choose MFC AppWizard (EXE). Accept all the defaults up to step 6. In step 6 choose CHtmlView as the base class.
If you look in your ProjectNameView.cpp file, youll see this line in the CProjectNameView::OnInitialUpdate( ) function:
Navigate2(_T("http://www.microsoft.com/visualc/"),NULL,NULL); |
Figure 12: Sample application
You can edit this line to have the application load a different URL from the Visual C++ page, or a local page. Compile and run this application to see the basic CHtmlView in action. Figure 12 shows the application running.
You can obtain on www.vcdj.com a more comprehensive DHTML sample that creates a CHtmlView and a CListView separated by a splitter. It then uses DHTML to enumerate the HTML elements in the CHtmlView and displays the results in the CListView. The end result is a DHTML explorer that you can use to view the DHTML object model of any HTML file! The sample includes a README.TXT file that describes the steps used to generate the application. Figure 13 shows the MFC 6.0 sample in action.
Figure 13: MFC 6.0 sample
For more information |
I hope this introduction to DHTML has started you thinking about some ways you can use this exciting new technology in your MFC-based applications. The possibilities are endless: applications that update from the Internet, completely dynamic applications, and countless others.