Re: How can I stop controls from executing default keyboard and mouse behavior?
From: Rob Kennedy (me_at_privacy.net)
Date: 01/29/04
- Next message: Sander Martens: "Formstyle"
- Previous message: Rob Kennedy: "Re: For loop failing on dell 800"
- In reply to: IDF: "How can I stop controls from executing default keyboard and mouse behavior?"
- Next in thread: IDF: "Re: How can I stop controls from executing default keyboard and mouse behavior?"
- Reply: IDF: "Re: How can I stop controls from executing default keyboard and mouse behavior?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Thu, 29 Jan 2004 11:13:01 -0600
IDF wrote:
> A TJvStringGrid "on" a TJvPageControl (technically the grid is on the
> form, but it looks like it's "on" the page control). I wanted to
> change tabs using the fairly standard Ctrl-PgUp and Ctrl-PgDn, but
> could not stop the TJvStringGrid (which usually has focus) from
> responding to the PgUp and PgDn keys which were always detected and
> acted upon even if the Ctrl keys were also being pressed. The grid
> scrolls itself when arrows, page keys, home and end are pressed.
> Ultimately I settled on Ctrl-N and Ctrl-P for switching tabs to avoid
> the problem.
Ctrl+N means New File. Ctrl+P means Print. If your program has the
ability to print or to start a new file, I'd expect those keystrokes to
initiate those actions, not navigate tabs, which is what Ctrl+Tab and
Ctrl+Shift+Tab are for.
If the grid is not really "on" the page control, then what is? If there
is nothing on the page control, then you might consider using a tab
control instead.
The keyboard handling for tab controls and page controls is done in the
cm_DialogKey message handler. By default, they handle the Ctrl+Tab and
Ctrl+Shift+Tab keystrokes. It shouldn't be too complicated to modify the
controls to handle your own keys, too. TJvPageControl has a
HandleGlobalTab property, which tells it to handle the navigation
keystrokes even if it wouldn't otherwise do so.
> A TJvSpinEdit. It increments and decrements itself with no event
> handler needed if you press up arrow or down arrow when it has focus.
> [...] I couldn't stop that built-in behavior, so my workaround was
> that my form-level code skips the increment/decrement whenever it
> sees that the spinedit has focus, otherwise I'd have a
> double-increment or double-decrement.
Did you try setting the ArrowKeys property to False?
> A TCheckListBox. I liked seeing the checkboxes for multi-selection,
> but I hated having to click in the itty bitty little checkboxes - I
> wanted to be able to click anywhere on the row to flip (set or clear)
> the selection.
The item-checking code occurs in the MouseDown method. It uses the
ItemAtPos method to find out which item is being clicked, and then
computes the check-box width using the ItemRect and GetCheckWidth
methods. You don't *need* a descendant component to fix this, but it
would be the prefered solution. Override TCheckListBox.MouseDown:
procedure TFullWidthCheckListBox.MouseDown(Button: TMouseButton; Shift:
TShiftState; X, Y: Integer);
var
Index: Integer;
begin
inherited;
// At this point, the item may have already been checked.
// This code is a mirror of the inherited MouseDown code -- it
// only acts when the mouse action occurs *outside* the check box.
if Button = mbLeft then begin
Index := ItemAtPos(Point(X, Y));
if (Index <> -1) and GetItemEnabled(Index) then begin
if not UseRightToLeftAlignment then begin
if X - ItemRect(Index).Left >= GetCheckWidth then
ToggleClickCheck(Index);
end else begin
Dec(X, ItemRect(Index).Right - GetCheckWidth);
if (X <= 0) or (X >= GetCheckWidth) then
ToggleClickCheck(Index);
end;
end;
end;
end;
You'll have to copy the implementation of ToggleClickCheck into your own
code since it's a private method, which can't be called by descendants.
> The general problem is controls executing built-in behavior that I
> can't disable or take control of.
And the general problem is that you just don't know where to look to
change how a control behaves. You're thinking as a user, but you need to
think as a developer.
When you thought about what causes a check box to change in a check list
box, you probably decided, "It changes when I click on it," and
proceeded to do something when the control was clicked. (To your credit,
you didn't try to solve this by handling the OnClick event!) But you
need to look a little deeper. Sure, the check changes when you click,
but why? And why does it only change when you click in certain areas and
not others? TO answer those questions, you need to look at the source
code. That's always the first place I look when something is behaving
strangely. For the TCheckListBox, I first looked for a wm_LButtonDown
message handler. Finding none, I looked at the MouseDown method, and it
became obvious that it was that method that toggled the check boxes. It
took a little analysis (using the term loosely) to figure out that the
coordinate calculations were determining whether the click occured
within the bounds of the check box.
> Now, I have some other problems: that form-level arrow key handling I
> described above is causing problems, because the arrow keys also
> seem to automatically serve as tab-key "synonyms," so not only does
> the spin control increment or decrement (at my command), but the
> focus gets tabbed around the controls on the form. The tab and
> shift-tab work just fine; how can I turn off this "next control",
> "previous control" tabbing for the arrow keys? Not just for up and
> down arrow, which I only want to control the spin edit; but also left
> arrow and right arrow, which I'm using as synonyms for two particular
> buttons (a previous and next button on the form)?
Just like the page control's tab switching, the arrow-key form
navigation occurs in a cm_DialogKey message handler. TCustomForm is the
class of interest this time. Changes will be a little more complicated
this time since you can't simply override the message handler and change
the key code. You'd need to do that before calling the inherited
handler. The inherited handler is what controls the navigation, but the
inherited inherited handler (the one in TWinControl) is what broadcasts
the key message to all the child controls, which is how other controls
become able to handle they keystrokes they want.
What I would try would be to override the cm_DialogKey handler in my
TForm descendant, but *not* call inherited. Instead, I would copy the
code I need from the inherited handlers and paste them into my own
handler. Then I'd just remove the part that deals with the arrow keys. I
would leave in the part that deals with the Tab key and the part that
calls Broadcast.
-- Rob
- Next message: Sander Martens: "Formstyle"
- Previous message: Rob Kennedy: "Re: For loop failing on dell 800"
- In reply to: IDF: "How can I stop controls from executing default keyboard and mouse behavior?"
- Next in thread: IDF: "Re: How can I stop controls from executing default keyboard and mouse behavior?"
- Reply: IDF: "Re: How can I stop controls from executing default keyboard and mouse behavior?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]