Win32 Editable TreeView and ListView Merged as One
Introduction
There are times when there is a need for a combination of the TreeView control along with the ListView control. A control that can present data in an expanding tree along with grid lines and editable columns. Unfortunately, such a control is not part of the Win32 basic controls (including those found within comctl32.lib). This article will show how to extend the TreeView control to meet this need. The included source files hold a complete TreeList control source that can be easily used in many projects. The project was written entirely in C, and with direct calls to the Win32 API without the use of any runtime library support (such as MFC and others). The reason behind this is to be as fast and as independent as possible. Furthermore, it can be merged with existing projects written in C without special modifications to the code.
I assume previous knowledge in Win32 native APIs, an understating of how a window works, and the way custom owner drawn controls are created. Since we are dealing with presenting complex data types, an of understanding linked lists, pointers, and not very common memory allocation techniques is required as well.
Now, having said that, we can safely continue and focus on the following aspects.
Using the code
Drawing the grid lines on top of the TreeView control
After having created the TreeView with CreateWindowEx
, we have to handle some of its messages in our Windows procedure. Most of the interesting messages comes in as WM_NOTIFY
message. The first thing we have to do is to extract the message hidden within the LPARAM
parameter. For doing this, we will cast the LPARAM
as a LPNMTVCUSTOMDRAW
pointer and examine its 'code
' member as shown below:
case WM_NOTIFY:
{
lpNMHeader = (LPNMHDR)lParam;
switch(lpNMHeader->code)
{
The next step is to respond to the NM_CUSTOMDRAW
message. By doing this, we can intervene in the control drawing process and extend it to our needs. Once again, we will cast the LPARAM
, this time to a LPNMTVCUSTOMDRAW
pointer and examine its nmcd.dwDrawStage
member. There are several stages in the control's creation process that we need to handle:
CDDS_PREPAINT |
Before painting the entire ListView control. |
CDDS_ITEMPREPAINT |
Before painting an item within the tree. |
CDDS_ITEMPOSTPAINT |
Just after the item is drawn. |
In each stage, we will have to redirect Windows to the next one, the purpose of this is to be able to do some work in the CDDS_ITEMPOSTPAINT
stage. Finally, when we get to the point where a break point stoops at CDDS_ITEMPOSTPAINT
, we can add the horizontal and vertical grid lines. The nmcd
structure member provides us, among other things, the control's DC and a handle to the tree item currently being drawn. With a mix of calls such as TreeView_GetItemRect()
, FillRect()
, DrawEdge()
, DrawText()
, we will draw those lines and the label's text on each of our columns.
Please refer to TreeLis.c\TreeListHandleMessages()
for more information.
The internal data type
This control has to store internally a dynamic tree along with the correct relations between each and every node. This is done be using the following type:
static struct tag_TreeListNode
{
int NodeDataCount; // Count of items in pNodeData
HTREEITEM TreeItemHandle; // Handle to the tree item (windows)
struct tag_TreeListNode *pParennt; // Node pointer to the parent
struct tag_TreeListNode *pSibling; // Node pointer to the first sibling
struct tag_TreeListNode *pBrother; // Node pointer to the first brother
TreeListNodeData **pNodeData; // Array of NodeData structures
// for each column
};
typedef struct tag_TreeListNode TreeListNode;
Each time we're adding a new node, we are allocating memory for this structure and tying it to its surrounding nodes (parent and possibly a sibling). Each node represents an element in the tree, but since we have columns, it holds the **pNodeData
pointer which is in turn being allocated to hold an array of the columns attached to our node.
Please refer to TreeList.c\TreeList_Internal_NodeAdd()
for more information.
Data validity check
Since we are heavily working with pointers and dynamically allocated memory, I have added a safe guard to the data type. Each time a node is linked with another node, I'm verifying its data integrity using CRC. Each time a node is created or modified, its CRC value is calculated and attached to it.
See TreeList.c\TreeList_Internal_CRCCreate()
and TreeList.c\TreeList_Internal_CRCCheck()
for more information.
The sample code (Container.c) and API usage
This sample file creates a dialog window and positions the control on top of it by attaching it to its WM_INITDIALOG
message in its Window procedure, as shown below:
INT_PTR CALLBACK WinWndProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_INITDIALOG : // This is the place to start the control
{
// Control setup..
TreeListInitControl(GetModuleHandle(NULL), hWndDlg, NULL,
&Container_ValidateEditRequest);
If you are creating the host window using CreateWidow()
, you can put the TreeList calls in the WM_CREATE
message. Don't forget to free the control's memory by calling TreeListDestroy()
while exiting the host window.
TreeListInitControl (HINSTANCE Instance, HWND ParentHwnd, RECT *pRect, TREELIST_CB *pFunc);
Init the control. I guess that if you are here, the Instance
and the parent window handler parameters are obvious. pRect
is the absolute position of the control on top of its parent window, and unfortunately for you, it's not implemented (yet).. sorry. That last parameter is a callback pointer to your edit request handler. It will be invoked whenever the caller wishes to edit a cell.
TreeListAddColumn(char *szColumnName,int Width);
Create the columns, make sure you set Width
= TREELIST_LAST_COLUMN
in your last column width param.
TreeListNodeAdd(NODE_HANDLE ParentHandle,TreeListNodeData *RowOfColumns,int ColumnsCount);
Add a node. Here you must specify the parent node handler (set NULL
for the root node), and an array of TreeListNodeData
structs that represent each column. Lastly, you must provide the elements count within this array. Following is a short description of the TreeListNodeData
struct. The call returns a handle to the node that was created, you can use this node to add the node's siblings.
static struct tag_TreeListNodeData
{
char Data [TREELIST_MAX_STRING +1]; // The string to display
BOOL Editable; // Is it an editable cell?
BOOL Numeric; // Is it a numeric cell?
void *pExternalPtr; // a caller pointer, will be sent back
// along with the call back function.
BOOL Altered; // Internal
long CRC; // Internal
};
typedef struct tag_TreeListNodeData TreeListNodeData;
The last thing to do is route the window messages to the control so we can handle them within the internal window procedure.
case WM_CLOSE:
{
TreeListDestroy(); // Kill and free the control info
EndDialog(hWndDlg, IDOK);
return TRUE;;
}
}
return TreeListHandleMessages(hWndDlg, Msg, wParam, lParam);
// TreeList Control handler
}
History
- Version 1.2: This is the initial version of this control.
发表评论
mhMFYL When I open up your Feed it seems to be a ton of junk, is the issue on my part?
Really enjoyed this blog.Much thanks again. Fantastic.
imp source I want to start selling hair bows. How do I get a website started and what are the costs?. How do I design it?.
This site truly has all the information and facts I needed concerning this subject and didn at know who to ask.
You made some good points there. I did a search on the topic and found most people will approve with your blog.
You have remarked very interesting details ! ps decent web site.
There is clearly a bunch to know about this. I suppose you made some nice points in features also.
Very good comments, i really love this site , i am happy to bookmarked and tell it to my friend, thanks for your sharing.
This content has a lot of great information that is apparently intended to make you think. There are excellent points made here and I agree on many. I like the way this content is written.
Thanks for the article post.Thanks Again. Great.
Utterly pent subject material, Really enjoyed reading through.
Rattling great info can be found on site.
Just Browsing While I was browsing today I saw a excellent article about
Thanks for sharing, this is a fantastic post.Really thank you! Really Cool.
wonderful issues altogether, you just received a emblem new reader. What could you recommend in regards to your put up that you simply made some days ago? Any certain?
Thanks, I ave recently been seeking for facts about this subject matter for ages and yours is the best I ave located so far.
Loving the info on this internet site , you have done outstanding job on the articles.
wow, awesome blog post.Thanks Again. Cool.
This is one awesome article post.Really thank you! Great.
very couple of web-sites that occur to become comprehensive beneath, from our point of view are undoubtedly well really worth checking out
Wow, wonderful weblog format! How long have you been running a blog for? you make blogging glance easy. The overall glance of your site is fantastic, let alone the content material!
Really appreciate you sharing this blog post.Thanks Again. Much obliged.
There is certainly a lot to know about this subject. I like all the points you ave made.
It as not that I want to replicate your web-site, but I really like the layout. Could you tell me which style are you using? Or was it tailor made?
look at skies (look for chemtrail in google) fake clouds blocking sunlight UK and USA govt as put chemicals in tap water and food to dumb down population research everything mentioned
Muchos Gracias for your article post.Really thank you! Really Great.
You completed a number of fine points there. I did a search on the topic and found mainly persons will go along with with your blog.
You got a very great website, Gladiola I observed it through yahoo.
Very informative blog post. Will read on
Strange but true. Your resource is expensive. At least it could be sold for good money on its auction!
Its not my first time to go to see this site, i am visiting this web site dailly and get good information from here every day.
See my scam i post here for get backlink
Thanks for the post.Really looking forward to read more. Great.
Looking forward to reading more. Great article post.Thanks Again. Keep writing.
Way cool! Some extremely valid points! I appreciate you penning this post and the rest of the site is also very good.
Some genuinely excellent info , Gladiolus I observed this.
Looking forward to reading more. Great article post.Really thank you! Great.
This unique blog is definitely educating as well as diverting. I have picked a bunch of handy stuff out of this amazing blog. I ad love to return again and again. Cheers!
You made some decent factors there. I looked on the internet for the difficulty and located most people will go together with along with your website.
It'аs really a great and useful piece of info. I'аm glad that you just shared this helpful info with us. Please keep us informed like this. Thank you for sharing.
In general, the earlier (or higher ranked on the search results page)
Your style is very unique in comparison to other folks I have read stuff from. Many thanks for posting when you have the opportunity, Guess I will just book mark this web site.
You can definitely see your expertise within the work you write. The sector hopes for even more passionate writers like you who aren at afraid to say how they believe. All the time follow your heart.
This awesome blog is without a doubt educating as well as informative. I have picked helluva helpful stuff out of it. I ad love to visit it again and again. Thanks a bunch!
There is noticeably a bunch to know about this. I consider you made various nice points in features also.
There is visibly a bunch to realize about this. I believe you made certain good points in features also.
Your style is unique in comparison to other folks I ave read stuff from. Thanks for posting when you have the opportunity, Guess I all just book mark this site.
The Birch of the Shadow I feel there may possibly become a couple duplicates, but an exceedingly handy listing! I have tweeted this. Several thanks for sharing!
You made some good points there. I did a search on the topic and found most people will go along with with your blog.
Im obliged for the blog post.Really thank you! Really Cool.