CPercentageCtrl






4.47/5 (9 votes)
An easy control to display and to modify percentages
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) orPC_VERTICAL
PC_VERTICALTEXT
(default) orPC_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.
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.