Teach Yourself Visual C++® 5 in 24 Hours

Previous chapterNext chapterContents


- Hour 20 -
Using ActiveX Controls

ActiveX controls enable you to reuse custom controls written for Windows. In this hour, I discuss ActiveX controls and how they are used. In this hour, you will learn

A small example at the end of the hour uses one of the ActiveX controls included with Visual C++.

What Is an ActiveX Control?

New Term: An ActiveX control is a reusable control that is packaged and available for use in your applications. ActiveX controls use Object Linking and Embedding (OLE) interfaces for communication to and from the control.

ActiveX controls can be developed for both the 16-bit and 32-bit versions of Windows. In addition, they have features that make them more attractive for distribution, such as support for licensing and localization into different languages.

A wide range of ActiveX controls is available. Later in this hour, you can follow the steps required to use the Microsoft FlexGrid control that is included with Visual C++, which enables you to write simple spreadsheet applications.

Why Use an ActiveX Control?

ActiveX controls are easy to use in your MFC-based applications because they have been designed for reuse. Developer Studio includes the Component and Controls Gallery, a tool that helps you easily integrate ActiveX controls into your MFC programs.

New Term: ActiveX controls communicate over well-defined interfaces that are understood by ActiveX controls and the programs that use them. These interfaces are used to pass information and events to and from the control.

Because ActiveX controls use a standard interface that is not specific to any particular programming language, ActiveX controls can be used by a variety of development tools. The ActiveX controls that you use today in a Visual C++ program can also be used with other tools, such as Access 95, Visual FoxPro, and Visual Basic.

ActiveX controls offer more functionality than is available with standard controls offered by Windows. For example, before the release of Windows 95, many VBX vendors offered VBX controls that were similar to tree view controls; these vendors are now offering ActiveX controls with features that are not available when using standard controls.

How Is an ActiveX Control Used?

New Term: An ActiveX event is a message that is sent from the control to the application that contains the control.

An ActiveX control always communicates with an ActiveX control container. Control containers understand the ActiveX control interfaces, as shown in Figure 20.1. An ActiveX control container is responsible for providing an environment in which the control can pass events to its owner and receive information from the outside world. The ActiveX control sends events to the ActiveX container when an event occurs inside the control. Mouse clicks, pressed buttons, and expiring timers are examples of events. The ActiveX container provides information to the control such as the natural or "ambient" background color and the default font.

Figure 20.1.
Messages sent to and from ActiveX controls in an MFC program.

New Term: An ActiveX property is an attribute that is applied to the control, such as a color or the height of a button.

New Term: An ActiveX method is a function that is exposed by the control and is called by the control's container.

When an ActiveX control container must communicate with an ActiveX control, it interacts with a set of properties and methods that are exposed by the ActiveX control. An example of an ActiveX property is the font or background color used by a control. An example of an ActiveX method is a function that sorts the items in a list control.

Every class derived from CWnd in an MFC application can be used as an ActiveX control container. The MFC class COleControl is used as a base class for all ActiveX controls created using MFC.

Using the Components and Controls Gallery

The Developer Studio Components and Controls Gallery is used to store reusable components that can be used in your MFC-based Windows projects. If you develop a class that you would like to reuse in future projects, you can add the class to the Gallery by following these steps:

1. Open the ClassView in the project workspace.

2. Right-click on the class name, and select Add to Gallery from the shortcut menu.

The most frequently used components stored in the Components and Controls Gallery are ActiveX controls. To display all the ActiveX controls available on your machine, open the Components and Controls Gallery by selecting Project | Add to Project | Components and Controls from the main menu.

After the Component Gallery dialog box is displayed, select Registered ActiveX Controls from the list box; this displays all the available ActiveX controls, as shown in Figure 20.2.

Figure 20.2.
Displaying available ActiveX controls in the Component Gallery.

Adding an ActiveX Control to the Dialog Editor

Before using an ActiveX control in a dialog box, you must insert the control into the dialog editor's control palette. To add an ActiveX control to the dialog editor, follow these steps:

1. Select one of the displayed ActiveX control icons.

2. From the Components and Controls Gallery dialog box, click the Insert button.

3. A message box will be displayed asking if you would like to insert the component. Click OK.

4. A list box containing classes that will be added to your project is displayed inside the Confirm Classes dialog box. Click OK to add the classes to your project.

5. Click the Close button to dismiss the Components and Controls Gallery dialog box.

The ActiveX control you selected is now included in the dialog editor's control palette. Open a dialog box for editing, and you see the new control palette, including the new ActiveX control.

You can use the new ActiveX control as you would any other control. To add it to a dialog box resource, drag and drop the control on the dialog box, or select the ActiveX control's icon and click on the dialog box resource.

Using ClassWizard to Configure an ActiveX Control

Before you can use the ActiveX control, it must be integrated into your project. As with any other control added to a dialog box, use ClassWizard to add message-handling functions and associate the control with an MFC object.

When adding a member variable associated with an ActiveX control, you can use ClassWizard as you would if the control were a button, list box, or another standard Windows control. Unlike standard Windows controls, each ActiveX control has a large number of variable types. In addition to the object used to interact with the control, every property exposed by the control can be associated with a variable.

An Example Using an ActiveX Custom Control

As an example of using an ActiveX control in an MFC-based project, you will now use the Microsoft FlexGrid control in a dialog box-based application. The grid control is used to create a small spreadsheet in the main dialog box.

To get started with the sample project, use AppWizard to create a dialog box-based application named CustomCtrl. In contrast to most of the book's other AppWizard examples, for this project you must keep one of the default options offered by the wizard. On the second AppWizard page, make sure the ActiveX Controls check box is selected. Selecting this option causes AppWizard to configure the project to be ActiveX control-ready.

What Is a Grid Control?

New Term: A grid control is a popular reusable component that is similar to a spreadsheet. Many suppliers of Visual Basic controls offer grid controls, and Microsoft includes with Developer Studio an ActiveX grid control named FlexGrid.

As you can probably guess by its name, a grid control is divided into a series of rectangles, or grids. Vertical lines separate the controls into columns, and horizontal lines divide the control into rows. The intersection of a row and column is known as a cell.

A grid control can contain a mixture of images and text. In most cases, text is used. You cannot directly edit the individual cells in a grid control. The grid control is strictly a read-only window, although there are ways to simulate cell editing that are discussed later this hour.

The most common use for a grid control is creating a small spreadsheet. If you want to display a small budget or other information, a grid control is ideal. In addition, you can use a grid control whenever you must arrange information into rows and columns. For example, a calendar dialog box might use a grid control to provide access to the individual days of the month.

A grid control spares you the work of creating and maintaining a large number of smaller controls. The grid control tracks the active cell, as well as the size and contents of each cell. When you need access to a particular cell, the grid control can provide that information through a function call. At a minimum, grid controls enable you to do the following:

Adding a Grid ActiveX Control to the Dialog Editor

To add a grid ActiveX control to the CustomCtrl project's main dialog box, you must first add the grid control to the dialog editor's control palette by following these steps:

1. Open the Components and Controls Gallery by selecting Project | Add to Project | Components and Controls from the main menu.

2. Display the available ActiveX controls by clicking Registered ActiveX Controls from the list box.

3. Select the Microsoft FlexGrid, version 5.0 Control icon and then click the Insert button; then click OK on the message box.

4. Accept the list of classes that will be added to the project by clicking OK.

5. Close the Components and Controls Gallery dialog box.

Adding a Grid Control to the Main Dialog Box

Before adding the grid control to the main dialog box, you must first load the dialog box resource into the dialog editor. Open the ResourceView in the project workspace. Open the dialog box resource folder and double-click the IDD_CUSTOMCTRL_DIALOG icon. This opens the dialog box resource inside the Developer Studio dialog editor.

To add a grid control, drag and drop the grid control from the control palette to the dialog box resource. For this example, you must also add an edit control with a resource ID of IDC_EDIT and a pushbutton control with an ID of IDC_CALC to the dialog box. The finished main dialog box resource is shown in Figure 20.3.

Figure 20.3.
The main dialog box resource for the CustomCtrl project.

The properties for the ActiveX grid control are provided in Table 20.1. Use the default properties for the edit control.

Table 20.1. Properties used for the ActiveX grid control.

Property Value
ID IDC_GRID
Rows 5
Cols 5
FixedRows 1
FixedCols 1
ScrollBars None

Initializing the Grid Control

Before adding the source code used to initialize the grid control, add member variables to the CCustomCtrlDlg class associated with the grid and edit controls. Using ClassWizard, add the member variables using the values from Table 20.2.

Table 20.2. Values used for the grid and edit control member variables.

Class Name Resource ID Category Type Variable Name
CCustomCtrlDlg IDC_EDIT Control CEdit m_edit
CCustomCtrlDlg IDC_GRID Control CMSFlexGrid m_grid


Just a Minute: Due to the way in which the Developer Studio tools are integrated, ClassWizard knows all about the Microsoft FlexGrid control and understands that the CMSFlexGrid class is used to interact with the control.

The main dialog box class, CCustomCtrlDlg, uses three new member variables to interact with the grid control.

Add the declarations for these variables to the CCustomCtrlDlg class, as shown in Listing 20.1. Add the source code to the implementation section, just after the // Implementation comment.

TYPE: Listing 20.1. Modifications to the CCustomCtrlDlg class declaration.

// Implementation
protected:
    BOOL    m_bEditing;
    int     m_nRow;

int m_nCol; The grid control must be initialized during the main dialog box's OnInitDialog member function. Add the source code from Listing 20.2 to the CCustomCtrlDlg::OnInitDialog member function, just after the // TODO comment.

TYPE: Listing 20.2. Initializing the ActiveX grid control in OnInitDialog.

// TODO: Add extra initialization here
m_bEditing = FALSE;
m_nRow = 1;
m_nCol = 1;
char*   arCols[4] = { "Jan", "Feb", "Mar", "Apr" };
char*   arRows[4] = { "Gas", "Phone", "MSN", "Total" };
m_grid.SetRow( 0 );
for( int nCol = 0; nCol < 4; nCol++ )
{
    m_grid.SetCol( nCol + 1 );
    m_grid.SetText( arCols[nCol] );
}
m_grid.SetCol( 0 );
for( int nRow = 0; nRow < 4; nRow++ )
{
    m_grid.SetRow( nRow + 1 );
    m_grid.SetText( arRows[nRow] );

} The source code added to the OnInitDialog function first initializes the new member variables added in Listing 20.1. The remaining code initializes the grid control.

The first for loop in Listing 20.2 sets the column headings to the first four months of the year. The next for loop sets the text used as row titles in the grid control. This short snippet of code shows how a grid control is typically used: Select a cell and then set or retrieve the text stored in that cell.

Detecting Grid Control Events

When an event occurs in the grid control, the control fires an event message to its container. The MFC framework translates this event message into a function call. To define the Click event message that is handled by the main dialog box, you use ClassWizard to add a message-handling function for the message, as shown in Table 20.3.

Table 20.3. ActiveX event messages handled by the CCustomCtrlDlg class.

Object ID Class Name Message Function
IDC_GRID CCustomCtrlDlg Click OnClickGrid

Add the source code for the CCustomCtrlDlg::OnClickGrid function provided in List- ing 20.3.

TYPE: Listing 20.3. Handling a mouse click event from the ActiveX grid control.

void CCustomCtrlDlg::OnClickGrid()
{
    CString szText = m_grid.GetText();
    if( m_bEditing == FALSE )
    {
        // Save the current grid position and set the edit flag.
        m_nRow = m_grid.GetRow();
        m_nCol = m_grid.GetCol();
        m_bEditing = TRUE;
        // Get the current grid text, and display it in the edit
        // control.
        szText = m_grid.GetText();
        m_edit.SetWindowText( szText );
        m_edit.ShowWindow( SW_SHOW );
        m_edit.SetFocus();
        m_edit.SetSel( 0, -1 );
    }
    else
    {
        // Roll up the edit control, and update the previous
        // grid position. You must save the current position,
        // go back to the old position, and then return to the
        // current position.
        int nCurrentRow = m_grid.GetRow();
        int nCurrentCol = m_grid.GetCol();
        m_grid.SetRow( m_nRow );
        m_grid.SetCol( m_nCol );
        m_grid.SetFocus();

        CString szEntry;
        m_edit.GetWindowText( szText );
        szEntry.Format("%01.2f", atof(szText) );

        m_edit.ShowWindow( SW_HIDE );
        m_grid.SetText( szEntry );
        m_bEditing = FALSE;
        m_grid.SetRow( nCurrentRow );
        m_grid.SetCol( nCurrentCol );
    }

} If the program receives a Click event, the m_bEditing flag is checked to see whether a cell is currently being edited. If not, the current row and column are collected from the grid control. This information is used later when the editing job is finished. The text stored in the current grid cell is retrieved and displayed in the edit control. Finally, the edit control text is selected, which makes it easy for a user to overwrite the current contents.

If a cell is being edited, the text contained in the edit control is stored in the grid. However, it must be stored in the cell that was originally clicked to open the edit control. This cell position was stored when the edit control was opened and is now used to reset the current row and column. The edit control text is reformatted into a standard dollars-and-cents format and stored in the original cell position.

The GetRow and GetCol functions provided by CGridCtrl are examples of ActiveX control methods that are exposed by the grid control. For a complete list of exposed methods, open the project workspace view and click the ClassView tab. Open the CGridCtrl class icon, and you see a list of the available member functions.

Recalculating the Grid Control Contents

Each column in the spreadsheet is recalculated when you click the Calculate button. Add a message-handling function to the CCustomCtrlDlg class that handles messages from the Calculate button, using the values from Table 20.4.

Table 20.4. Messages handled by the CCustomCtrlDlg class.

Object ID Class Name Message Function
IDC_CALC CCustomCtrlDlg BN_CLICKED OnCalc

Add the source code in Listing 20.4 to the CCustomCtrlDlg::OnCalc member function.

TYPE: Listing 20.4. Recalculating the contents of the ActiveX grid control.

void CCustomCtrlDlg::OnCalc()
{
    // Close current editing job, if any.
    if( m_bEditing != FALSE )
    {
        CString szEntry, szText;
        m_edit.GetWindowText( szText );
        szEntry.Format("%01.2f", atof(szText) );
        m_edit.ShowWindow( SW_HIDE );
        m_grid.SetText( szEntry );
        m_bEditing = FALSE;
    }
    for( int nCol = 1; nCol < 5; nCol++ )
    {
        double  dTotal = 0.0;
        m_grid.SetCol( nCol );
        for( int nRow = 1; nRow < 4; nRow++ )
        {
            m_grid.SetRow( nRow );
            CString szCell = m_grid.GetText();
            dTotal += atof( szCell );
        }
        CString szTotal;
        szTotal.Format( "%01.2f", dTotal );
        m_grid.SetRow( 4 );
        m_grid.SetText( szTotal );
    }

} Compile and run the CustomCtrl example. The grid control is initially empty. Clicking on a cell displays the edit control, which enables you to enter or change the cell's contents. If you click on the cell again, the value from the edit control is moved into the cell, and the edit control is hidden. Clicking the Calculate button totals each column in the grid control and hides the edit control. Figure 20.4 shows the CustomCtrl main dialog box with some of the grid cells filled in.

Figure 20.4.
The CustomCtrl project's main dialog box.

Summary

In this hour, you learned about ActiveX controls and the Developer Studio tools that are used with them. As part of the discussion, you created an example that used an ActiveX grid control as a small spreadsheet.

Q&A

Q How can I determine which events are provided by an ActiveX control?

A After the ActiveX control is added to your project, you can use ClassWizard to examine the events that are generated by the control.

Q How can I reuse controls installed on my computer by other applications?

A Most commercial controls are licensed; they cannot be used to design new applications without the proper ActiveX licensing file. Some controls can be used for evaluation purposes, even without a license--to be sure, contact the control vendor.

Workshop

The Workshop is designed to help you anticipate possible questions, review what you've learned, and begin thinking ahead to putting your knowledge into practice. The answers to the quiz are in Appendix B, "Quiz Answers."

Quiz

1. Where are reusable components stored in Developer Studio?

2. What are some other development tools that support creating and using ActiveX controls?

3. What are some examples of events sent from an ActiveX control?

4. What are some examples of properties exposed by ActiveX controls?

5. What ActiveX control is often used to model a small spreadsheet?

6. True or False: You can edit directly in a grid cell.

7. What AppWizard option must be selected to allow an ActiveX control to work properly?

8. What is an ActiveX method?

9. True or False: ActiveX controls can be developed only for 32-bit systems.

Exercises

1. Modify the CustomCtrl project so that 12 months are displayed in the grid and totals are provided for each row as well as for columns.

2. Modify the CustomCtrl project so that the grid is recalculated automatically.


Previous chapterNext chapterContents


Macmillan Computer Publishing USA

© Copyright, Macmillan Computer Publishing. All rights reserved.