Introduction
Frequently, different kind of information must be presented to the user in two dimensional form. Often, to do this, we can use ListView or TreeView controls, but sometimes this is not appropriate, or it is hard to code or cannot be used in their native form. Besides, we wish keep difference between elements and display them in appropriate form (e.g., one element show a color table, another show a text or image, and so on). Therefore, We need to have a flexible mode to operate. Control presented here implements a such array of items (like array or matrix in mathematics) which are freely drawn by user. An array is, for example, an image or a color table or whatever information that can be presented in two dimensions (third dimension can be implemented using TabControl as show in demo program). Control assist user in the items arrangement, in the resize of control, in the scroll and in the notify of events inherent the control itself. All items of the array have same size (i.e. width and height), that the control will use to arranging them into rectangle of its client area. Dimensions (i.e. columns and rows) and item size can be changed by the user in any instant, columns or rows can be fixed or dynamic (control will compute them at any change). Since each item will be drawn by user, any kind of things can be drawn on it. To do this, control pass to the user a Device Context (DC) specific for the item that is drawing. User paint the given DC and the control will render it to its window at the appropriated position (based on current scroll position and items arrangement).
Control creation
Array control is implemented by class CArrayCtrl
which was inherit from CWnd class. Constructor method initialize members variables and destroyer method is not used. The control's window class has name "ArrayControlClass" and will be register at the first call of create method. Control is created using method Create
which synopsis is:
BOOL CArrayCtrl::Create(DWORD dwStyle, const CRect& rect,
CWnd* pParent, UINT nID, const CSize& itemsize);
where
dwStyle specifies the control style attributes
WS_CHILD
WS_VISIBLE
WS_BORDER
ACS_TOOLTIP
ACS_TTBALLOON
ACS_BALLOONTIP
ACS_GRIDLINES
ACS_CLIENTEDGE
ACS_USERDATA
rect
pParent
nID
itemsize
The following code show how to create such control
CArrayCtrl* pArrayCtrl;
CSize ItemSize(32,64);
CRect rControl(8,8,200,100);
pArrayCtrl = new CArrayCtrl;
pArrayCtrl->Create(WS_CHILD | WS_VISIBLE | WS_BORDER
| ACS_BALLOONTIP | ACS_GRIDLINES,
rControl, pParentWnd, ID_ARRAY, ItemSize);
After this, window is displayed on screen but none item is visible. You have two mode to specify the items to the control. You can use method
SetItemsCount
(int nItems)
that force the control to start item-paint process, or method
AddItem(int nItem, LPARAM dwData)
that insert a new item into the control based to
nItem
value. It can be an item index (such as 5) and the control will insert new item after that, or the special item
ACAI_TOP
and
ACAI_BOTTOM
(default), meaning of which is obvious. Since
AddItem
method will redraw control's window each time item is added, we must suspend redrawing process until all items are been added. To do this you will use the
SetRedraw(BOOL bDraw)
method to stop the drawing process (
bDraw=FALSE
) and then restart it (
bDraw=TRUE
). This code snippet show it:
pArrayCtrl->SetRedraw(FALSE);
while( ... )
{
... prepare data item ...
pArrayCtrl->AddItem(dwData);
}
pArrayCtrl->SetRedraw(TRUE);
If you previously know the items count, you can use
SetItemsCount
method in this way:
... control is already been created ...
pArrayCtrl->SetRedraw(FALSE);
pArrayCtrl->SetItemsCount(100);
for(i=0; i<100; i++)
{
... prepare data item ...
pArrayCtrl->SetItemData(i, dwData);
}
pArrayCtrl->SetRedraw(TRUE);
Naturally, if you don't need to have userdata associated to the items, you can call above methods without call SetRedraw.
Methods
There are several methods grouped by category and it will be listed with a brief description. For more specific information on code utilization you should look source code implementation and demo.
General
UINT GetCtrlId ();
void SetCtrlData (LPARAM dwData);
LPARAM GetCtrlData ();
void SetToolTip (DWORD ttstyle);
void SetCursor (HCURSOR hCursor);
void SetRedraw (BOOL bResize);
void Activate (BOOL bFlag);
Items
void SetItemCount (int nItems);
int GetItemCount ();
DWORD GetItemState (int nItem);
int GetRowIndex (int nItem);
int GetRowIndex ();
int GetColumnIndex (int nItem);
int GetColumnIndex ();
void AddItem (int nItem, LPARAM dwData);
void AddItem (LPARAM dwData)
void DrawItem (int nItem);
void RemoveItem (int nItem);
void RemoveAllItems ();
LPARAM SetItemData (int nItem, LPARAM dwData);
LPARAM GetItemData (int nItem);
Sizing and dimensioning
void SetItemSize (int width, int height);
void SetItemSize (CSize* pSize);
void SetDimension (int nCount, int obj);
void SetDimension (int nCount);
int GetDimension (int* dimtype);
int GetWidth ();
int GetHeight ();
void GetItemSize (CSize* pSize);
int GetItemWidth ();
int GetItemHeight ();
void SetColumns (int nCol);
void SetRows (int nRow);
int GetColumns ();
int GetRows ();
Colouring
void SetBkColor (COLORREF crBack);
void SetGridColor (COLORREF crGrid);
void SetColors (COLORREF crBack, COLORREF crGrid);
COLORREF GetBkColor ();
COLORREF GetGridColor ();
void SetTipColor (COLORREF crBkg, COLORREF crTxt);
Selection and Scrolling
void SelectItem (int nItem);
void ActivateItem (int nItem);
void ActivateItem ();
int GetSelectedItem ();
int GetHitItem ();
void SetScrollSize (int nSBVers, int nSBObj, int nSize);
int GetScrollSize (int nSBVers, int nSBObj);
void Scroll (int nSBVers, UINT nSBCode);
void Scroll (int nSBVers, UINT nSBCode, UINT nPos);
void VertScroll (UINT nSBCode);
void VertScroll (UINT nSBCode, UINT nPos);
void HorzScroll (UINT nSBCode);
void HorzScroll (UINT nSBCode, UINT nPos);
void EnsureVisible (int nItem);
BOOL IsVisible (int nItem);
Grid Lines
void SetGridLines (BOOL bActive);
BOOL GetGridLines ();
void SetGridThickness (int nThickness);
int GetGridThickness ();
Notification process
Control send to parent window some notification messages using the WM_NOTIFY
form. It is sent by control to its parent window when an event has occurred or the control requires some information. Events which notification is required are listed below:
- mouse action over control
- item draw
- item deletion
- tooltip event
You can mapping the message by
ON_NOTIFY(wNotifyCode, CtrlId, memberFunction)
or
ON_NOTIFY_RANGE(wNotifyCode, CtrlIdFirst, CtrlIdLast, memberFunction)
Your member functions must be declared with the following prototypes:
afx_msg void memberFunction(NMHDR* pNotifyStruct,
LRESULT* result);
or
afx_msg void memberFunction(UINT CtrlId, NMHDR* pNotifyStruct,
LRESULT* result);
where the parameters are:
CtrlId the child identifier of the control that sent the notification.
pNotifyStruct a pointer to the notification structure, as described above.
result a pointer to the result code you’ll set before you return.
WM_NOTIFY
messages contain the ID of the control sending the message in
wParam
and a pointer to an
NMHDR
structure in
lParam
. This structure is followed by a related event structure that has an
NMHDR
structure as its first member. Note that since the
NMHDR
member is first, a pointer to this structure can be used as either a pointer to an
NMHDR
or as a pointer to the structure depending on what type of event is, and you must cast it to proper structure.
For mouse activation events control send an ACITEMACTIVATE
which have this declaration:
typedef struct tagACITEMACTIVATE
{
NMHDR hdr;
CArrayCtrl* pControl;
int nItem;
DWORD dwState;
int nRow;
int nColumn;
CPoint ptAction;
UINT nKeyFlags;
LPARAM dwParam;
}
ACITEMACTIVATE, *LPACITEMACTIVATE;
The field
code
of the
NMHDR
structure will report the event id:
ACN_CLICK
ACN_RCLICK
ACN_DBCLICK
For item draw and deletion events control send an
ACITEMINFO
which have this declaration:
typedef struct tagACITEMINFO
{
NMHDR hdr;
CArrayCtrl* pControl;
int nItem;
DWORD dwState;
int nRow;
int nColumn;
CDC* pDC;
int nWidth;
int nHeight;
LPARAM dwParam;
}
ACITEMINFO, *LPACITEMINFO;
The field
code
of the NMHDR structure will report the event id:
ACN_DRAWITEM
ACN_DELETEITEM
On item deletion only pControl
, nItem
and dwParam
fields are filled with meaningful information. For tooltip events control send an ACTOOLTIPINFO
which have this declaration:
typedef struct tagACTOOLTIPINFO
{
NMHDR hdr;
CArrayCtrl* pControl;
int nItem;
DWORD dwState;
int nRow;
int nColumn;
LPTSTR lpszTipText;
LPARAM dwParam;
}
ACTOOLTIPINFO, *LPACTOOLTIPINFO;
For the time being, the field
code
of the NMHDR structure will only report the event id:
ACN_NEEDTIPTEXT Tooltip require a text
The demo program
Demo program creates four controls to show any kind of operation performed with Array control. zbr> First and second control are CArrayCtrl
which show images, icons and text loaded by selecting a folder. Images will be shown as thumbnail, while icons and text will be shown as they are. A CxImage class, by Davide Pizzolato (see his article), is used to load images. I have used the related LIB built on my computer and I have included the original header file. The right button of the mouse show two menus: one if pointer is over an item and another if pointer is over a control but not over an item (know as item-menu and control-menu) that enable user to choose various operation.
Third control show an image selected from above controls and splashed on it. Selected icon will be shown using IconEdit program (.ico file extension must be associated to this via desktop) and text using Notepad. Other stuff can be chosen. There isn't menu associated to this control. Fourth control is a TabCtrl used for contrasting color test. It has ten items that specify the color Brightness value, and each item has an array control which items specify the Saturation and Hue values. This is a 3-dimensional control. By select an item, a new window will be displayed. In this window you can see two rectangle coloured with contrasting color of the background color: left rectangle is computed by alucardx algorithm (see article on general section) and right rectangle is computed by my own. At the side of each there are related color information. Two small icons rating the goodness of algorithms.
Enhancements and improvements
This is a list of open issues about CArrayCtrl
control:
- Make internal use of TabControl to implement 3-D array (this isn't a real limitation)
- Use Vector template to manage user data
- Sending
WM_NOTIFY
for mouse movements
- Make item management more complex (with more to use defaults)
- Implement items hot-tracking
- Make each item a mini-window with a own life
- Link each item to a thread to perform asynchronous operation
History
- This is the version 1 modification 0. I don't believe that all bugs were discovered.
I'm working in a big Mobile Telecommunication company. I am a System Programmer. My main task is the integration between Host application and distributed Open-systems and workstations, picture processing and graphic.