|
||
The
tree-view and list-view controls support label editing. For a tree-view,
the TVS_EDITLABELS style must be specified; for a list-view,
LVS_EDITLABELS is required. When label editing is enabled, clicking on
an item’s label results in an edit control being displayed to allow
the user to enter a new name for the item. When
editing begins, the control sends a notification - TVN_BEGINLABELEDIT
for a tree-view, LVN_BEGINLABELEDIT for a list-view. Label editing can
be prevented for any particular item by returning a nonzero value from
the message handler. Similarly, a notification is sent when editing
ends - TVN_ENDLABELEDIT for a tree-view, LVN_ENDLABELEDIT for a
list-view, unsurprisingly. So
far this seems very simple, and indeed it is, if the control is being
used as a regular child window, for example as a view pane. However,
if the control is in a dialog then strange things may happen. Clicking
on an item’s label causes the edit control to appear as expected,
but any attempt to enter text causes the edit control to disappear
along with the entire dialog! This is rather undesirable, to say the
least. The
problem here, as is explained in Knowledge Base Q130692, is that the
edit control is created with an ID of 1, which happens also to be the
value of IDOK,
the ID typically used for the ‘OK’ button. When the text in the
edit control changes, it sends notifications such as EN_CHANGE to the
tree or list-view, which for some reason forwards these notifications
on to the dialog window. The upshot is that the dialog thinks the
‘OK’ has been pressed, and dismisses itself. The
solution is to have the ‘OK’ command handler check the window
handle in lParam against that of the edit control. Commands coming
from the edit control should be discarded. The edit control is
retreived by sending a TVM_GETEDITCONTROL or LVM_GETEDITCONTROL
message. These messages can be sent each time the window handle is
needed, but it is more efficient to store the handle in a member
variable when label editing begins, and set the variable to NULL when
the edit finishes. There
is an additional twist when using a tree-view. Now we can enter text
into the label edit control, but when the enter or escape key is
pressed, once again the dialog dismisses itself. The problem is that
the dialog manager is trapping these keys, mapping the enter key to
the default ID and the escape key to IDCANCEL. This is basically due
to a bug in the tree-view and is documented in Knowledge Base article
Q130691. The article suggests subclassing the edit control so that it
returns DLGC_WANTALLKEYS
in response to the WM_GETDLGCODE message. It then says to send
TVM_ENDEDITLABELNOW to the tree-view in response to WM_CHAR messages
for VK_RETURN and VK_CANCEL. In fact, the subclass procedure never
receives these keystrokes (at least on Windows 2000), but fortunately
the label editing ends without further intervention. As
ever, there is yet another twist. Q130691
says to unsubclass the edit control in response to TVN_ENDLABELEDIT.
However, by that time, the edit control’s window procedure has for
some reason changed from what it was set to by subclassing in
TVN_BEGINLABELEDIT. This causes ‘polite’ unsubclassing (such as
ATL’s UnsubclassWindow) to fail. There is a choice between
‘forcing’ the unsubclassing, or just leaving the edit control
subclassed until it is destroyed at the very end of the label edit
operation. It is not strictly necessary to subclass the edit control. The command handlers for the default ID and IDCANCEL could detect whether a label edit is in progress and, if so, end it by sending a TVM_ENDEDITLABELNOW message. However, the subclassing approach is more generic, and does not depend on knowing the default ID. ATL’s CContainedWindow class makes it rather easy to subclass the edit control using an alternate message map, with no need to derive a new class. Addendum Knowledge Base article Q130691 was updated on June 28 2002, taking my comments into account. |
||
Home | Last updated on 16 July 2002. |
|