How to get notification for chk box in CTreeCtrl
I want to handle notification when i click chk box
in treeview, but i don't see any notification message which allows this.
[132 byte] By [
Rajeev] at [2007-11-10 12:52:06]

# 2 Re: How to get notification for chk box in CTreeCtrl
"Rajeev" <rpahuja@logicpp.com> wrote:
>
>I want to handle notification when i click chk box
>in treeview, but i don't see any notification message which allows this.
I found this to be a very frustrating problem in my own treeview program,
and I just found a solution yesterday. The WM_LBUTTONDOWN notification is
sent in response to a click on a checkbox, or on any other part of the tree.
(Before, I was trying to use WM_LBUTTONUP, which for some reason only responded
to a double-click.)
Use the Class Wizard to create a function that responds to WM_LBUTTONDOWN.
The following code will solve your problem:
void MyView::OnLButtonDown(UINT nFlags, CPoint point)
{
CTreeView::OnLButtonDown(nFlags, point); //Call base class function
BOOL CheckState;
HTREEITEM hItem = GetTreeCtrl().HitTest(point, &nFlags); //Find out what
item in tree was clicked on
CheckState = GetTreeCtrl().GetCheck(hItem); //Find out if item has
been checked or unchecked
# 3 Re: How to get notification for chk box in CTreeCtrl
My solution is still not entirely satisfactory, because it is also possible
to check a box by selecting the item and pressing the space bar. I presently
have two handlers: the one I gave you before, and a similar one that responds
to a WM_CHAR message. The second one tests whether nChar is equal to 32 (a
spacebar press), and then calls GetTreeCtrl().GetSelectedItem() to find out
which item was checked. The rest is the same.
OnSelChanged doesn't work, because it is possible to check a checkbox without
changing the selection.
I have tried using Spy++ to see what messages are generated. There doesn't
seem to be any message specifically for updating a checkbox. The only one
that occurs every time a checkbox is changed is WM_ERASEBKGD. That might
be the best message to handle for a checkbox, but I think it would be inefficient.
It would require stepping through the entire tree control and testing the
state of each checkbox every time the message occurred.
Anyone else have any better ideas?
Cliff Lewis
# 4 Re: How to get notification for chk box in CTreeCtrl
"Cliff Lewis" <clewis@gwis.com> wrote:
>
>Anyone else have any better ideas?
Yeah!
Let M$ solve crap like this!
They have a comparable thing with SysListView32 and there they have some
form of notification:
LVN_ITEMCHANGED, LVN_ITEMCHANGING. If M$ would have done the job right or
finished it, the
SysTreeView32 should have had something like that... Anyways...
I ended up implementing WM_LBUTTONDOWN, WM_LBUTTONUP, en TVN_KEYDOWN for
a
CTreeCtrl derived class.
In OnLButtonDown with member HitTest you can determine where the mouse was
clicked.
I check it with TVHT_ONITEMSTATEICON. You will have to remember the item
being clicked on. Than,
under certain conditions you will want to call the base class implementation
and in certain cases you
do not want to do that.
// Check if the TVS_CHECKBOXES style is set for this control.
if ( GetStyle () & TVS_CHECKBOXES )
{
// Check if the left mouse button has been pressed while the mouse
// pointer was on a state-icon. If so, remember which tree item it
// was on, otherwise perform normal processing.
// Notice that the complete default implementation for the SysTreeView32
// is being bypassed by not calling the base class member in case
// of a click on the state-icon.
HTREEITEM item;
UINT where;
if ( ( ( item = HitTest ( point, &where ) ) != 0
) &&
( where & TVHT_ONITEMSTATEICON
) )
state = item;
else
{
state = 0;
CTreeCtrl :: OnLButtonDown ( flag, point );
}
}
else
CTreeCtrl :: OnLButtonDown ( flag, point );
Than in OnLButtonUp you will have to check if the mouse button was release
on the same spot as it
was being pressed. If so, you want to issue an notification, if not you call
the base class implementation:
// Check if the TVS_CHECKBOXES style is set for this control.
if ( GetStyle () & TVS_CHECKBOXES )
{
// Check if the left mouse button has been released while the mouse
// pointer was on the same state-icon as it was when the left mouse
// button was pressed. If so, change the state of the item, i.e. if
// the checkbox was set clear it or otherwise and perform the callback
// for this action.
// Notice that the complete default implementation for the SysTreeView32
// is being bypassed by not calling the base class member in case
// of a click on the state-icon.
HTREEITEM item;
UINT where;
if ( ( ( item = HitTest ( point, &where ) ) != 0
) &&
( where & TVHT_ONITEMSTATEICON
) &&
( item == state
) )
{
Toggle ( item );
TV_TOGGLE tv_toggle ( item, flag, point );
LRESULT result;
toggle.Perform ( this, &tv_toggle, &result );
}
else
CTreeCtrl :: OnLButtonUp ( flag, point );
state = 0;
}
else
CTreeCtrl :: OnLButtonUp ( flag, point );
That will properly take care of the left mouse button being clicked on a
state icon.
The next thing is to also implement the TVN_KEYDOWN...
// Check if the TVS_CHECKBOXES style is set for this control.
if ( GetStyle () & TVS_CHECKBOXES )
{
// Determine whether or not the pressed key was the space bar.
TV_KEYDOWN *keydown = ( TV_KEYDOWN * ) nmhdr;
if ( keydown -> wVKey == VK_SPACE )
{
// Determine the selected tree item.
HTREEITEM item = GetSelectedItem ();
if ( item != 0 )
{
// Set the tree item state to the state it should have after
// processing of the key down.
Toggle ( item );
// Perform the callback. The tree item state had to be set before
// because a callback most likely will check the state of the
tree
// item.
TV_TOGGLE tv_toggle ( item, keydown -> wVKey, keydown ->
flags );
toggle.Perform ( this, &tv_toggle, result );
// Set the tree item state back to the state it has before. This
// because whether or not TRUE is being returned, the default
// implementation of SysTreeView32 is always being processed
for
// a key down!
Toggle ( item );
*result = 0;
// return ( TRUE );
}
return ( FALSE );
}
*result = 0;
}
return ( FALSE );
I think this should work. Seeing what I had to do to get it all working correctly
I got rather upset...
I am sure this works since it has been implemented this way in an end user
program.
HTH
Don't worry, be Kneppie!
Jan