Click here to Skip to main content
15,886,069 members
Articles / Desktop Programming / MFC
Article

Advanced Checkers Control

Rate me:
Please Sign up or sign in to vote.
4.68/5 (8 votes)
28 Nov 2001Zlib6 min read 92.2K   2.4K   46   10
A High performance "Disk Optimizer" like status display class
 [Sample 1 Image - 37K]
fig. 1: Sample with normal dialog template

Introduction

During the development of a telecommunication server monitoring application I encountered the requirement to display the status of a huge number of lines and resources. One interesting way to give the user a general idea of the overall status while maintaining the possibility to get also more detailed status information, is to use a control that displays the status with small colored boxes. This technique is also used in several disk optimizing programs in order to show the user the progress and status of the operation.

After evaluating some checker controls, I decided to develop my own version, since I had a set of requirements that I didn't find in the evaluated implementations. These requirements are:

  • Dynamic resize capability
  • Dynamic Scroll Bar
  • Static and dynamic ToolTips
  • Live ToolTip update
  • Unicode aware
  • Low memory footprint
  • Low memory fragmentation
  • Low impact on system performance

The result is CCheckersCtrl, a CWnd-derived class that can be used either as a control in dialog boxes, property sheets and form views, or as a child window.

 [Sample 2 Image - 22K]
fig. 2: The control with scrollbar

Usage

If you use the checkers control in a dialog template, simply add a user draw button to the dialog template and associate it with a control variable in class wizard. You should activate the following styles for the button:

Visible, Tab Stop, Owner Draw, Client
Edge
. In Class Wizard assign a control variable to the button. After this you should change the type of the control variable in the dialog class from CButton to CCheckersCtrl. That's all. Now you are ready to use it.

Before starting, let me explain some basic concepts: Each box is handled as an Item like items in CListView. Each item is identified by an index number that starts from 0 (zero) and keeps three kinds of information:

  1. The item status. This is a BYTE. The status is displayed as a color.
  2. An optional item data of type DWORD.
  3. An optional ToolTip-Text that can be set statically for an item, or dynamically via an overridable method when needed for display.

The control stores some global information about the visualization of the items:

  1. The maximal and minimal size of the boxes
  2. An array of colors for each possible status

In order to use the control you must not specify all this stuff, since the control is initialized with decent defaults: the item size is set to a range from 6 to 24 pixels and the color array contains the 16 standard windows colors. BTW: if you set a status for an item that is greater than the highest element in the color array, the control does not crash: the color is determined with the following formula:

COLORREF crUsedColor = m_crColorArray[bItemState % m_iNumColors];

If you do not want the boxes to resize automatically, simply set the item size range to the same value.

During the lifetime of the CCheckersCtrl you can reconfigure, resize, add items, delete items, set values and attributes in any order. The control is able to handle all these operations. The only limitation of this version is that the control is not thread-safe, so please DO NOT use it from multiple threads. In a future version I will make it thread-safe.

Reference

The style of the methods resembles the style of standard item oriented MFC controls like CListView, so there should not be much to explain.

BOOL CCheckersCtrl::SetSizeLimits (int iMinSize, int iMaxSize, 
                                    BOOL bRedraw = TRUE);

With this function you define in which range the boxes can be automatically resized. If you do not want the boxes to automatically resize, specify the same value for iMinSize and iMaxSize.

int CCheckersCtrl::GetMinSize () const;
int CCheckersCtrl::GetMaxSize () const;
BOOL CCheckersCtrl::IsAutoResize () const;

With these functions you can retrieve the size range for the boxes.

int CCheckersCtrl::GetItemCount () const;

Retrieves the number of items in a checkers control.

BOOL CCheckersCtrl::SetItemCount (
    int     iCheckers,
    BYTE    bInitialState = 0,
    DWORD   dwData = 0,
    LPCTSTR pszTip = LPSTR_TEXTCALLBACK,
    BOOL    bRedraw = TRUE
);

Sets the number of items in a checker control. If the number of items is larger than the number of existing items, new items are created with the specified state, item data and tool tip text. If LPSTR_TEXTCALLBACK is used, the tool tip text will be requested just in time by invoking the overridable method CCheckersCtrl::OnGetToolTipText.

BOOL CCheckersCtrl::SetColorsArray (COLORREF *pColors, 
                    int iNumColors, BOOL bRedraw = TRUE)

Specifies the array of colors to be used to represent each state. Since the state is a BYTE the maximal size for the array should not exceed 256.

void CCheckersCtrl::SetDefaultColors (BOOL bRedraw = TRUE)

Resets the array of colors to be used to represent each state to the 16 standard windows colors.

BOOL CCheckersCtrl::SetItemData (int nItem, DWORD dwData);
DWORD CCheckersCtrl::GetItemData (int nItem) const;

These functions allow you to associate an application defined value to each item and to retrieve it.

BOOL CCheckersCtrl::SetItemState (int nItem, BYTE bState, 
                                BOOL bRedraw = TRUE);
BYTE CCheckersCtrl::GetItemState (int nItem) const;

These functions allow you to get or modify the state of an item. Changes are reflected immediately.

BOOL CCheckersCtrl::SetItemStateArray (BYTE *baState, 
                int cbSize = -1, BOOL bRedraw = TRUE);
BOOL CCheckersCtrl::GetItemStateArray (BYTE *baState, 
                                    int cbSize) const;

These functions allow you to get or modify the state of all items. Changes are reflected immediately.

BOOL CCheckersCtrl::SetItemToolTip (int nItem, 
                LPCTSTR pszTip = LPSTR_TEXTCALLBACK);
BOOL CCheckersCtrl::GetItemToolTip (int nItem, 
                CString& str) const

These functions allow you to get or modify the text of an item's tooltip. Changes are reflected immediately.

BOOL CCheckersCtrl::Create (DWORD dwStyle, const RECT& rect, 
                        CWnd* pParentWnd, UINT nID);

Use this function to create a checkers control as a child window. The function is used like in any other common control. There are no specific styles for the checker control.

BOOL CCheckersCtrl::ResetState (BYTE bState = 0, BOOL bRedraw = TRUE);

Resets the state of all items to the specified state.

BOOL CCheckersCtrl::InsertItem (
    int     nItem,
    BYTE    bInitialState   = 0,
    DWORD   dwData          = 0,
    LPCTSTR pszTip          = LPSTR_TEXTCALLBACK,
    BOOL    bRedraw         = TRUE
);

BOOL CCheckersCtrl::InsertItems (
    int     nItem,
    int     nCount          = 1,
    BYTE    bInitialState   = 0,
    DWORD   dwData          = 0, LPCTSTR pszTip = LPSTR_TEXTCALLBACK,
    BOOL    bRedraw         = TRUE
);

Inserts new items at the specified location. Like in CCheckersCtrl::SetItemCount the initial state, item data and tool tip text can be specified.

BOOL CCheckersCtrl::DeleteItem (int nItem, BOOL bRedraw = TRUE);
BOOL CCheckersCtrl::DeleteItems (int nItem, int nCount = 1, 
                                BOOL bRedraw = TRUE);

Deletes items from the specified location.

BOOL CCheckersCtrl::DeleteAllItems ();

Deletes all items.

int CCheckersCtrl::FindItem (DWORD dwData) const;

Permits to find an item based on the associated application defined value. This method returns the index of the found item. If no matching item is found, -1 is returned.

int CCheckersCtrl::HitTest (CPoint pt) const;

Returns the item index corresponding to the specified client coordinates. If no matching item is found, -1 is returned.

BOOL CCheckersCtrl::EnsureVisible (int nItem, BOOL bPartialOK);

Makes sure that the specified item is visible. If needed the item is scrolled into view.

BOOL CCheckersCtrl::EnableToolTips (BOOL bEnable);

Permits to enable or disable the tool tip feature. If the feature is disabled, all static tool tips are removed. When tool tips are enabled, all items will get dynamic tool tips.

Advanced functions

CToolTipCtrl & CCheckersCtrl::GetToolTipCtrl ();
const CToolTipCtrl & CCheckersCtrl::GetToolTipCtrl () const;

Retrieves the internal ToolTip Control

Overridables

You can derive your own class from CCheckersCtrl in order to implement custom behavior for tool tips and mouse clicks. For this purpose CCheckersCtrl offers 4 overridable methods.

virtual BOOL CCheckersCtrl::OnGetToolTipText (
    int             nItem,
    BYTE            bState,
    DWORD           dwParam,
    TOOLTIPTEXT *   pTTT
);

If you have specified items with dynamic tool tips (LPSTR_TEXTCALLBACK), this method is called when the text for a tool tip is requested. You get the item index nItem, its state bState, the associated application value dwData and a pointer to a TOOLTIPTEXT structure in which you can return the tool tip text. Take a look at the demo implementation:

BOOL CMyChecker::OnGetToolTipText (int nItem, BYTE bState, 
                        DWORD dwParam, TOOLTIPTEXT *pTTT)
{
    m_csBuffer.Format (
        _T("Tooltip for Item %i\n\nStatus: %u\nParameter: %lu (0x%08x)"),
        nItem,
        (UINT) bState,
        dwParam, dwParam
    );
    pTTT->lpszText = (LPTSTR) (LPCTSTR) m_csBuffer;
    return TRUE;
}
virtual BOOL CCheckersCtrl::OnLeftClick (
    BOOL            bDoubleClick,
    UINT            nFlags,
    CPoint          point,
    int             nItem,
    BYTE            bState,
    DWORD           dwParam
);

virtual BOOL CCheckersCtrl::OnMiddleClick (
    BOOL            bDoubleClick,
    UINT            nFlags,
    CPoint          point,
    int             nItem,
    BYTE            bState,
    DWORD           dwParam
);

virtual BOOL CCheckersCtrl::OnRightClick (
    BOOL            bDoubleClick,
    UINT            nFlags,
    CPoint          point,
    int             nItem,
    BYTE            bState,
    DWORD           dwParam
);

These three overridables permit you to handle mouse clicks on the control. The nFlags parameter indicates whether various virtual keys are down. This parameter can be any combination of the following values:

  • MK_CONTROL: Set if CTRL key is down.
  • MK_LBUTTON: Set if left mouse button is down.
  • MK_MBUTTON: Set if middle mouse button is down.
  • MK_SHIFT: Set if SHIFT key is down

The point parameter contains the client coordinates relative to the control on which the mouse click occurred. Take a look at the implementation of the context menu in the demo application:

BOOL CMyChecker::OnRightClick (BOOL bDoubleClick, UINT nFlags, 
    CPoint point, int nItem, BYTE bState, DWORD dwParam)
{
    if ( bDoubleClick ) {
        return TRUE;
    }
    CMenu menu;
    if ( menu.LoadMenu (IDR_CONTEXT_MENU) ) {
        CMenu *pPopUp = menu.GetSubMenu (0);
        if ( pPopUp ) {
            ClientToScreen (&point);
            m_iLastClick = nItem;
            pPopUp->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, 
                    point.x, point.y, GetParent ());
        }
    }
    return TRUE;
}

Version History

Version 1.3

  • Fixed Class Wizard Comments
  • Fixed initialization
  • Repaired mouse click behavior

Version 1.2

  • Fixed refresh bug in SetDefaultColors
  • Added deferred redraw capability
  • Adapted demo application

Version 1.1

  • Improved documentation
  • Added context menu to demo application

Version 1.0

Initial revision

License

This article, along with any associated source code and files, is licensed under The zlib/libpng License


Written By
Product Manager PSI Logistics GmbH
Germany Germany
I started programming computers in 1979. After years of management and administration application programming, I started to work mainly in the telecommunication sector in 1986. While working at Cycos AG (formerly known as PP-COM GmbH) from 1992 to 1999 I was involved in the development of core and GUI components of their telematic server MRS for ISDN. After that I worked for a telecommunication company named Infitel International N.V. that produces software for open telecommunication services. After a long stop at Cycos AG, I worked for several other companies like Siemens Enterprise Communications, Axxom Software AG and PSI Logistics GmbH.

If you are curious about my other Computer related activities and previous projects, visit YeaSoft International

Comments and Discussions

 
GeneralScroolBar Pin
Sasa Kajic16-Oct-05 10:24
Sasa Kajic16-Oct-05 10:24 
Generalthrow...exception Pin
Balkrishna Talele29-Dec-03 0:37
Balkrishna Talele29-Dec-03 0:37 
GeneralSetColorsArray malloc error Pin
Darren74013-Jun-03 9:58
Darren74013-Jun-03 9:58 
GeneralRe: SetColorsArray malloc error Pin
bitpusher24-Nov-04 13:04
bitpusher24-Nov-04 13:04 
GeneralJust what I'm looking for... Pin
Anonymous18-Dec-02 5:03
Anonymous18-Dec-02 5:03 
GeneralNice Control Pin
Paul Belikian26-Sep-02 12:12
Paul Belikian26-Sep-02 12:12 
Generala bug? Pin
7-Apr-02 8:06
suss7-Apr-02 8:06 
GeneralRe: a bug? Pin
Paul Belikian26-Sep-02 12:10
Paul Belikian26-Sep-02 12:10 
GeneralRe: a bug? Pin
Kybert31-Jul-03 7:44
Kybert31-Jul-03 7:44 
GeneralRe: a bug? Pin
Balkrishna Talele29-Dec-03 0:26
Balkrishna Talele29-Dec-03 0:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.