65.9K
CodeProject is changing. Read more.
Home

CPercentageCtrl

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.47/5 (9 votes)

Mar 12, 2002

CPOL

2 min read

viewsIcon

81844

downloadIcon

1471

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.

OSZAR »