Board index » delphi » ComboBox.OnChange Events from Keyboard Input

ComboBox.OnChange Events from Keyboard Input

I make use of many TComboBox components of the style DropDownList, attaching
code to the onChange to perform various actions.  Most of my combos simply
store a selection, and I check to be sure the selection has changed before
updating anything.  Therefore I was not concerned with when and how many
times the onChange event may occur during a single mouse or keyboard
selection.  But now I need a combo to make a selection that causes a read to
a remote database (in order to update a TreeView).  In addition, in some
instances I need to display a warning dialog before allowing a selection to
happen.  If the mouse is used to make a selection, there are no problems
with this - only one onChange is fired when the selection is made.  Keyboard
input is another thing.  My two problems are:

     - When navigating the combo via the arrow keys, while it is dropped
down, onChange events are generated right away.  This causes the unwanted
behavior of a network access for each keystroke.  Is there anyway using the
standard combo to avoid this problem? (they supplied an 'onDropDown' event,
why not an 'onCloseUp'?)  If not, I guess I am looking for a custom
component with such an event, or one that acts like the combo box in a
Windows 'File Open' dialog (and still has all the normal TComboBox
properties and methods).

     - If I display my warning dialog after a keyboard selection in the
combo, and then attempt to reset the ItemIndex to its previous value, I get
2 onChange events, which causes my warning to be displayed twice.  Normally,
programmatic change of ItemIndex does *not* fire the onChange in a combo.
Why in this case?  Am I missing something or this odd behavior?

Any suggestions or pointers at all will be much appreciated.

Garret Marotta  <gmaro...@pcn.com>

 

Re:ComboBox.OnChange Events from Keyboard Input


<all snipped>

Quote
> That's because you have actually changed the selection
> by moving the highlight to a new item.

I agree with a lot of what Kurt said, but the quote above is not entirely
correct. Just look at the behaviour of the combobox in Windows Explorer.
Your selection is not changed until the drop-down is closed up (or more
specifically, closed up in a certain way).

The rule is, while the combo is dropped down the up/down arrow keys have no
effect on the selection (from the user's point of view). Only when the
dropdown closes up due to the user pressing the Enter key, or selecting an
item with the mouse is the change acted on. If you close the dropdown by
pressing Esc, or clicking outside the dropdown then no change is made to
the selection.

To make this handling easier and consitent across applications, Microsoft
introduced the CBN_SELENDOK and CBN_SELENDCANCEL notifications. You should
process the selection change when you get CBN_SELENDOK and only then.

Unforunately, Delphi doesn't provide events for these notifications so you
have to create a derived control that does expose them.
--
Tim Knipe | Plasmatech Software Design | http://plasmatech.com
Explorer controls for Delphi, C++Builder and soon ActiveX!

Re:ComboBox.OnChange Events from Keyboard Input


What you could do, although there is very possibly a better solution,
is have some kind of check in your onChange event, to check whether or
not the combobox is in its drop down state or not (ie, if it is, then
dont do all the processing).  You can do this using :

If SendMessage (ComboBox1.Handle, CB_GETDROPPEDSTATE, 0, 0) = 0 then
begin
  // do the stuff you want done on change but not when the list is
showing
end;

Unfortunately though, this will mean that when you drop down the box
and hit enter, the code will not be executed since the drop down box
will still be down when onChange is called.  so you will need to add
say an onKeyDown method using the enter key or something like that.

Like i said this is a pretty cruddy way of getting around it, but it
might get you on the right track anyway.

Tanya

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/   Now offering spam-free web-based newsreading

Re:ComboBox.OnChange Events from Keyboard Input


Tim -

 > I agree with a lot of what Kurt said, but the quote above is not entirely
 > correct. Just look at the behaviour of the combobox in Windows Explorer.
 > Your selection is not changed until the drop-down is closed up (or more
 > specifically, closed up in a certain way).

I sort of have to disagree with you here. First, the parent is sent a
CBN_SELCHANGE method when arrowing through the list. Second, if the
control is asked what the currently selected item is, it will answer
with whatever you have arrowed to.

In order to make productive use of the CBN_SELENDOK or
CBN_SELENDCANCEL messages, you have to first note the CBN_DROPDOWN
message, grab the current selection index, and save it. Then on every
CBN_SELCHANGE message, you have to overwrite the edit portion of the
combo box (which is itself a problem, particularly when the style is
drop-down-list.) Finally, when you do get the CBN_SELENDxxxx
notification, you either have to explicitly reset the selection to the
original (in the case of cancel) or the edit portion to the final
choice (in the case of OK.)

The unfortunate aspect of this is that the messages go to the parent
of the control, so unless the parent is clever enough to pass them on
to the child before processing them (and be prepared to ignore them if
the control says to), it's hard to write reasonably clean code to
handle such. Ideally, the message should have been sent to the child
in the first place, which could ignore it and Windows could pass it up
the chain. But that isn't the way it was designed.

Good luck.

Kurt

Re:ComboBox.OnChange Events from Keyboard Input


Quote
Kurt Barthelmess (TeamB) wrote:
> I sort of have to disagree with you here. First, the parent is sent
> a CBN_SELCHANGE method when arrowing through the list. Second,
> if the control is asked what the currently selected item is, it will
> answer with whatever you have arrowed to.

Both points are true. However...

Quote
> In order to make productive use of the CBN_SELENDOK or
> CBN_SELENDCANCEL messages, you have to first note the
> CBN_DROPDOWN... [snip description of process]

The control does all that for you. All you have to do is this:

1. Don't do anything in OnChange.

2. When you get CBN_SELENDOK you do what you have done in OnChange.

That's all there is! Windows will handle the rest.

Quote
> ... so unless the parent is clever enough to pass them
> on to the child before processing them (and be prepared
> to ignore them if the control says to),

Fortunately for us, Delphi is such a clever parent. :) The CBN_*
notifications come through the WM_COMMAND handler of the parent. Delphi
sends these back to the originator as CN_COMMAND messages which will give
your control first crack at the CBN_* notifications.

I can assure you that the things mentioned here actually do work. They have
been part of the Shell Control Pack since 1996!

Quote
> Ideally, the message should have been sent to the child
> in the first place

Nowadays yes, but when the 'parent does the work' idea was designed it
saved you subclassing (in the Windows sense) every dialog control. Of
course, now even MFC subclasses every control so what was a good idea then
is a pain in the {*word*82}now.

--
Tim Knipe | Plasmatech Software Design | http://plasmatech.com
Explorer controls for Delphi, C++Builder and soon ActiveX!

Re:ComboBox.OnChange Events from Keyboard Input


Tim -

 > The control does all that for you. All you have to do is this:

 > 1. Don't do anything in OnChange.
 > 2. When you get CBN_SELENDOK you do what you have done in OnChange.
 > That's all there is! Windows will handle the rest.

But if the change is canceled, the selection has already been made.
Somebody has to restore the original selection.

 > Fortunately for us, Delphi is such a clever parent. :) The CBN_*
 > notifications come through the WM_COMMAND handler of the parent. Delphi
 > sends these back to the originator as CN_COMMAND messages which will give
 > your control first crack at the CBN_* notifications.

I'm aware of that<g>.

 > Nowadays yes, but when the 'parent does the work' idea was designed it
 > saved you subclassing (in the Windows sense) every dialog control. Of
 > course, now even MFC subclasses every control so what was a good idea then
 > is a pain in the {*word*82}now.

My point exactly.

Good luck.

Kurt

Re:ComboBox.OnChange Events from Keyboard Input


Quote
Kurt Barthelmess (TeamB) wrote:

> But if the change is canceled, the selection has already been made.
> Somebody has to restore the original selection.

You are right. I checked out the behaviour of MS combo boxes and they're
inconsistent with themselves (why am I not surprised?).

* WinNT4/sp3 explorer works correctly and sets the selection back when Esc
is pressed.

* Early versions of Win95 do not set it back, but they don't apply the
change either because they don't get the CBN_SELENDOK message.

* The common open/save dialogs behave as if you pressed Enter when you hit
Esc.

--
Tim Knipe | Plasmatech Software Design | http://plasmatech.com
Explorer controls for Delphi, C++Builder and ActiveX!

Other Threads