HOME
Login
Change Info
Logout


TUTORIALS

C, C++
Win32
Java
Visual Basic
MFC
DCOM
Networking
C#
Perl
HTML
XML
ASP
PHP
Javascript
Other

DOWNLOADS
ITCLib
SourceVizor meets the notification, reporting, and admin needs of teams using Microsoft Visual SourceSafe.
Free 30-day trial!


Using Windows Common Controls

by Marshall Brain

Questions, comments, suggestions - We want to hear from you! Comment on this article Get the Acrobat PDF File For This Article Get Adobe Acrobat Reader
Most downloads under 500KB


In Windows 3.1 and earlier versions of Windows NT, Windows supports six different controls. These controls are available in Visual C++ under the dialog editor, and can also be created in code using MFC classes for each of the controls. With Windows 95 came a whole new set of controls that add better appearance and functionality to dialogs that use them. The Windows common controls are supported in the following environments:

  • Windows 95, 98, ME
  • Windows NT (version 3.51 or later), Windows 2000
  • Win32s, version 1.3

The different controls available are listed below:

  • CListCtrl - List control (also called list view control)
  • CTreeCtrl - Tree control (also called tree view control)
  • CSpinButtonCtrl - Spin button control (also called up-down control)
  • CImageList - Image list
  • CRichEditCtrl - Rich edit control
  • CSliderCtrl - Slider control (also called trackbar)
  • CProgressCtrl - Progress control
  • CAnimateCtrl - Animation control
  • CHeaderCtrl - Header control
  • CHotKeyCtrl - Hot key control

These controls already exist within MFC and are rarely used outside of MFC:

  • CStatusBarCtrl - Status window (CStatusBar)
  • CTabCtrl - Tab control (Property Sheets)
  • CToolBarCtrl - Toolbar control
  • CToolTipCtrl - Tool tip control

Most of these controls are demonstrated in a huge and extensive MFC example program called CMNCTRLS, available from the developer' network CD.

A Simple Example Using the Spin Button, List, and Tree Controls

The common controls are remarkably easy to use once you see a bit of example code. You could spend a week studying each control in detail, but for normal use there is not a lot of complexity. For an example of how complex things can get, see the code in the CMNCTRLS example mentioned above.

In this example we will create a simple example that demonstrates how to use the spin control, the new list control and the tree control. Take the following steps:

Step 1

Use the AppWizard to create a new project named NewCtrls with the following options:

  • Single document
  • Remove the Docking toolbar, Initial status bar, and Printing and print preview options
  • Change the number of files in the recent file list to zero
  • Change the Base class of the CNewCtrlsView from CView to CFormView

Open the Dialog resource IDD_NEWCTRLS_FORM. Enlarge the template and remove the existing static control. Add a Tree control, List control (make sure you use the new list box), Spin control, and an Edit box. Change the properties for the following controls:

  • Change the list control View style to Report
  • Enable the tree control styles Has buttons, Has lines, and Lines at root
  • Enable the spin control styles Auto buddy and Set buddy integer

In order for the Auto buddy style of the spin control to know which control is its "buddy" we must change the Tab Order so the edit box and the spin control are in sequential order with the edit box first.

Step 2 - CSpinButtonCtrl

If you compile and run the application now, you will notice that the spin button control is fully functional. Its buddy edit box contains the value zero. When you press the down arrow the value increases, and when you press the up arrow the value decreases. This somewhat odd behavior is because the default range for the spin button has the maximum set to zero and the minimum set to 100. Since the maximum value is less than the minimum value the function of the arrow buttons is reversed. We will use the control's SetRange method to change these values to achieve the desired functionality.

Use the ClassWizard to add Control member variables for the tree, list, and spin button controls in the CNewCtrlsView class (m_ctlTreeCtrl, m_ctlListCtrl, and m_ctlSpinButtonCtrl, respectively). Also add the OnInitialUpdate handler to the class and add a call to SetRange:


void CNewCtrlsView::OnInitialUpdate()
{
    CFormView::OnInitialUpdate();
    m_ctlSpinButtonCtrl.SetRange( -10, 10 );
}

Now the spin button control will allow you to change the edit control's value from -10 to 10. You can use other methods of the spin button control to change other properties such as the base (decimal or hex) and the adjustment rate (acceleration).

Step 3 - CListCtrl

The new list control is more complex than the standard list box. Because the list control has four different ways to display itself, it has much more functionality. For this example we will demonstrate the Report view mode of the list control. In this mode, the list control looks a lot like a standard list box, except it more easily supports multiple columns which can be sorted and resized.

First we will fill the list control with three rows and three columns. Each row is made up of an item and two subitems. The subitems are only visible in Report mode. The other three modes only show the item label for each element in the list. To add a column to the list use the InsertColumn method. Call it once for each column you want in the list. Inserting items and subitems is a two part process. First call InsertItem to insert an item in the list. Once there is an item in the list you use SetItemText to set the text for each subitem.


void CNewCtrlsView::OnInitialUpdate()
{
    CFormView::OnInitialUpdate();

    m_ctlSpinButtonCtrl.SetRange( -10, 10 );

    m_ctlListCtrl.InsertColumn( 0, "Item" );
    m_ctlListCtrl.InsertColumn( 1, "Subitem 1" );
    m_ctlListCtrl.InsertColumn( 2, "Subitem 2" );

    int nItem;

    nItem = m_ctlListCtrl.InsertItem( 0, "Item A" );
    m_ctlListCtrl.SetItemText( nItem, 1, "Subitem A1" );
    m_ctlListCtrl.SetItemText( nItem, 2, "Subitem A2" );

    nItem = m_ctlListCtrl.InsertItem( 0, "Item B" );
    m_ctlListCtrl.SetItemText( nItem, 1, "Subitem B1" );
    m_ctlListCtrl.SetItemText( nItem, 2, "Subitem B2" );

    nItem = m_ctlListCtrl.InsertItem( 0, "Item C" );
    m_ctlListCtrl.SetItemText( nItem, 1, "Subitem C1" );
    m_ctlListCtrl.SetItemText( nItem, 2, "Subitem C2" );
}

Now you can run the application and see that the list has three rows and three columns. The columns can be resized by dragging the column dividers in the list header. Double-clicking the divider resizes the column so it exactly fits the column's contents.

A common thing to do with the list control is to allow the user to sort each column when the column header is clicked. To add this functionality to our example we have to do three things. First we have to know when a list column header is clicked. We can do this by adding a handler for the LVN_COLUMNCLICK message. When a column is clicked, we can sort the list on the selected column.


void CNewCtrlsView::OnColumnclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

    int nColumn = pNMListView->iSubItem;
    ASSERT( (nColumn >= 0) && (nColumn <= 2) );
    m_ctlListCtrl.SortItems(CompareFunc, nColumn);

    *pResult = 0;
}

This code tells the list control to call the CompareFunc function for each item in the list and to sort the items based on the result of the function. The arguments that are passed to CompareFunc are the item data for each item in the list, as well as the second argument that was passed to SortItems. We can use this sort data to tell the sort function which column to base the sorting on. The only thing missing is the item data for each item in the list. Currently our items don't have any associated item data.


void CNewCtrlsView::OnInitialUpdate()
{
    ...
    nItem = m_ctlListCtrl.InsertItem( 0, "Item A" );
    m_ctlListCtrl.SetItemText( nItem, 1, "Subitem A1" );
    m_ctlListCtrl.SetItemText( nItem, 2, "Subitem A2" );
    m_ctlListCtrl.SetItemData( nItem, 0 );
    ...
    m_ctlListCtrl.SetItemText( nItem, 2, "Subitem B2" );
    m_ctlListCtrl.SetItemData( nItem, 1 );
    ...
    m_ctlListCtrl.SetItemText( nItem, 2, "Subitem C2" );
    m_ctlListCtrl.SetItemData( nItem, 2 );
}

Add the sort function declaration to the header file for the CNewCtrlsView class:


static int CALLBACK CompareFunc(LPARAM, LPARAM, LPARAM);

Add the sort function implementation to the .cpp file for the CNewCtrlsView class:


int CNewCtrlsView::CompareFunc(LPARAM lParam1, LPARAM lParam2,
    LPARAM lParamSort)
{
    switch(lParamSort)
    {
    case 0: // First column, sort A, B, C
        return lParam1 - lParam2;
        break;
    case 1: // Second column, sort C, B, A
        return lParam2 - lParam1;
        break;
    case 2: // Third column, no change
        return 0;
        break;

    default: // Invalid column
        ASSERT(FALSE);
        return 0;
    }
}

Notice that this function is defined as a static member function. This is because this function will be called as a callback from system, which expects the function to behave like a normal C callback function. For this compare function we have hard wired the function to sort the first column in the order of the item data elements (A, B, C), the second column sorts in reverse order (C, B, A) and the third column will not change the sorting of the list. If you wanted to make the sorting more intelligent you could make the item data a pointer to a structure that describes each item. Then you could sort based on the column text or a currency.

Step 4 - CTreeCtrl

The list control organized items and subitems in a linear form. The tree control organizes items and subitems in a hierarchical tree structure. Each item becomes a parent with subitems as its children. The most common example of a tree structure is the file system. Each directory is a parent which can contain other directories and files as children. If a parent has children, it can be expanded to show its children or collapsed to hide its children. As with the list control, you insert items into a tree control using its InsertItem method. There are many overloaded versions of this method. The most simple version of the method has arguments for the item label text and its position in the tree. InsertItem returns a handle to the new item. You can use this handle in other InsertItem calls to add children to a parent.


void CNewCtrlsView::OnInitialUpdate()
{
    CFormView::OnInitialUpdate();
    ...
    HTREEITEM hTreeRoot;
    HTREEITEM hTreeChild;

    hTreeRoot = m_ctlTreeCtrl.InsertItem( "Root1" );
    m_ctlTreeCtrl.InsertItem( "Child1 of Root1", hTreeRoot );
    hTreeChild = m_ctlTreeCtrl.InsertItem( "Child2 of Root1", hTreeRoot );
    m_ctlTreeCtrl.InsertItem( "Child1 of Child2 of Root1", hTreeChild );
    m_ctlTreeCtrl.InsertItem( "Child3 of Root1", hTreeRoot );

    hTreeRoot = m_ctlTreeCtrl.InsertItem( "Root2" );
    m_ctlTreeCtrl.InsertItem( "Child1 of Root2", hTreeRoot );
    hTreeChild = m_ctlTreeCtrl.InsertItem( "Child2 of Root2", hTreeRoot );
    m_ctlTreeCtrl.InsertItem( "Child1 of Child2 of Root2", hTreeChild );
    m_ctlTreeCtrl.InsertItem( "Child3 of Root2", hTreeRoot );

    hTreeRoot = m_ctlTreeCtrl.InsertItem( "Root3" );
    m_ctlTreeCtrl.InsertItem( "Child1 of Root3", hTreeRoot );
    hTreeChild = m_ctlTreeCtrl.InsertItem( "Child2 of Root3", hTreeRoot );
    m_ctlTreeCtrl.InsertItem( "Child1 of Child2 of Root3", hTreeChild );
    m_ctlTreeCtrl.InsertItem( "Child3 of Root3", hTreeRoot );
}

In this example, all the items in the tree are kept in the order they are added. The tree controls can also be sorted alphabetically or by a custom algorithm. If we wanted to sort the items in the list we could add the TVI_SORT flag as another argument to the InsertItem calls:


hTreeChild = m_ctlTreeCtrl.InsertItem( "Child2 of Root3",
			hTreeRoot, TVI_SORT );

Conclusion

You can see from these examples that the simple use of common controls is extremely straightforward. You can learn about more complicated aspects of each control either through the documentation or the CMNCTRLS example mentioned above.

Developed Under:

Visual C++ 6.0 Service Pack 5


Featured Article

An Introduction to C#
By Joey Mingrone

Register Today!


100% FREE

Members enjoy these benefits:
Access to ITI Downloads
Access to more articles and tutorials
Optional weekly newsletter
And more...

Click here to register
Or
Click here to log in



© 2008 Interface Technologies, Inc. All Rights Reserved
Questions or Comments? devcentral AT iticentral DOT com
PRIVACY POLICY