Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CPercentageCtrl

0.00/5 (No votes)
20 Mar 2002 1  
An easy control to display and to modify percentages

Sample Image - PercentageCtrl.gif

Introduction

CPercentageCtrl is an easy control to display the ratio between many entities, as the used space and the free space, or the composition of a cocktail :)

Obviously user can modify ratios dragging the blocks' edges.

Using the control

Add an instance of the control as member data in your dialog;
class CMyDialog : public CDialog
{
    ...
    CPercentageCtrl m_percentage;
    ...
}

Then initialize the control in OnInitDialog() using the Create(...) function

BOOL CMyDialog::OnInitDialog()
{
    ...
    CRect r(10,10, 200, 50);
    m_percentage.Create(NULL, NULL, WS_VISIBLE | WS_BORDER, r, 
                           this, ID_PERCENTAGE);
    ...
}

To add a block is really easy, you must only specify its weight:

m_percentage.AddBlock(250);

In any block you can select the color and a text to be displayed: the text can be formatted using CString::Format(...) (or printf) style, the color is the usual RGB value

m_percentage.AddBlock(250, "%0.1f%%", RGB(200,255,255));

Blocks' dimension must be an integer value, but you can set a double multiplier that is used to display the text. For example, if you want to show the value as "25.1" you should insert a 251 dimension and set the multiplier to 0.1

m_percentage.AddBlock(251);
m_percentage.SetMultiplier(0.1);

Some options are available:

  • PC_HORIZONTAL (default) or PC_VERTICAL
  • PC_VERTICALTEXT (default) or PC_HORIZONTALTEXT
  • PC_READONLY
  • PC_ALWAYSSHOWTEXT: the control will show the text even if it is not completely contained in the block; otherwise the control display text only if it is completely contained in his block.
  • PC_TEXTELLIPSIS: if it's needed, the control does a text ellipsis to shorten the text as it could be contained in the block.
You can set these options using the command SetOptions(int):
m_percentage.SetOptions(PC_HORIZONTAL | PC_ALWAYSSHOWTEXT);

Any time that the user modifies the dimension of a block, the control sends a message. You can intercept this message inserting in the messages map the macro:

<code>ON_REGISTERED_MESSAGE(PERCENTAGE_CHANGED,FunctionName)

For example:

BEGIN_MESSAGE_MAP(CPercentageCtrlDemoDlg, CDialog)
    //{{AFX_MSG_MAP(CPercentageCtrlDemoDlg)

    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP

    ON_REGISTERED_MESSAGE(PERCENTAGE_CHANGED,OnPercentageChanged)
END_MESSAGE_MAP()
In this case remember to declare the message PERCENTAGE_CHANGED in this way:
extern const UINT PERCENTAGE_CHANGED;
The called function will receive in WPARAM the handle of the calling control, and in LPARAM the index of the first modified block (when a user modifies a block, he modifies also that one at its right). The OnPercentageChanged function could be:
LRESULT MyDialog::OnPercentageChanged(WPARAM WParam, LPARAM LParam)
{
    if ((HWND)WParam == m_percentage.m_hWnd)
    {
        int data1 = m_percentage.GetData((int)LParam);
        int data2 = m_percentage.GetData((int)LParam+1);
        ....
    }
}

Developing notes

I chose to allow the insertion of entire values with a multiplier in order to avoid errors of approximation in the visualization of the text
(e.g. 99 = 24 + 24 + 24 + 27 = 24.4 + 24.4 + 24.4 + 26.8 = 100 = 24.6 + 24.6 + 24.6 + 26.2 = 25 + 25 + 25 + 26 = 101)

I used Keith Rule's CMemDC to avoid flickering. You can find his class and an article here at codeproject :)

Obviously the code compiles cleanly under the warning level 4 :)

History

21 Mar 2002 - serious GDI resources leaks fixed.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here