Re: msflexgrid with ctrl-pgup & ctrl-pgdn
- From: Mike Williams <gagamomo@xxxxxxxxxxx>
- Date: Sat, 9 May 2009 02:44:12 -0700 (PDT)
On 9 May, 01:17, Rick <rick-pau...@xxxxxxxxx> wrote:
IMO, It seems like videosoft's msflexgrid is rather
greedy in taking all the navigation key combos,
many of which do the same thing.
Lots of controls eat various keys, either because of the nature of the
control or sometimes simply because it is a "Windows thing". For
example, unless there is only one control on your Form then the Tab
key will not get to the Form's KeyPreview unless all of their Tabstop
properties are set to False. It is still possible for your VB app to
get at all keys pressed by the user though, even the navigation keys
when your MSFlexGrid has the focus, but you need to use subclassing to
do it by setting up a keyboard hook. Such hooks can be system wide
(where your VB app can "see" all keypresses even when some other app
has the focus) or application wide (where your VB app can "see" all
keypresses only when a Form in your own app, or something on it, has
the focus). In almost all cases the latter is the best option, unless
you are doing something a bit unusual. You need to take the usual
"subclassing" precautions to avoid crashing the IDE of course,
specifically with respect to how you terminate your app when running
in the IDE (you should never use the Run / End menu for example
because it prevents the Form's Unload event from running) and the IDE
is likely to crash if your app generates an error while running in the
IDE, but running as a compiled exe is fine. There are some "safe
subclassing in the IDE" routines on vbaccelerator but personally I
don't use them myself and once I have got the subclassing working okay
I just disable it when performing other work on my app and enable it
again when I compile the exe.
Anyway, here's a simple example. There are two blocks of code, one for
a standard module and the other for your Form. When peforming
subclassing it is advisable for your code to get out of the subclassed
procedure fairly quickly and since I don't know how much work your own
code will be doing in response to the keys I have used a standard VB
Timer as a "one shot" so that the subclassed procedure ends very
quickly and your own code in response to the key can safely run in the
Timer event, which occurs about ten milliseconds after the key was
pressed. I can't remember now why I decided to use a Timer as a one
shot in this example, as opposed to the alternative of using
PostMessage to trigger an event, but I think there must have been a
good reason for it at the time. Also, when subclassing in this way you
get a choice as to what you want to do with the key when you have
picked it up and done what you want with it. You can either allow the
system (your VB app) to respond to the key in the normal way or you
can alternatively "eat" the key so that as far as the rest of your app
is concerned it was never pressed in the first place. In this example
I've "eaten" the key (the PageUp and the PageDown keys) in order to
prevent the MSFlexgrid responding to those keys in its normal way
(since that is what I assume you would prefer). But if you want to
change that behaviour you can do so (there is a short note in the code
explaining what to do if you want to make that change).
To try the example, first place an otherwise unused Timer Control on
the Form that contains your MSFlexGrid and add the following code into
your Form Load and Unload events (if your Timer is not called Timer1
then amend the code accordingly):
Private Sub Form_Load()
Timer1.Enabled = True
Timer1.Interval = 0
HookKeyboard Timer1
End Sub
Private Sub Form_Unload(Cancel As Integer)
UnHookKeyboard
End Sub
Then use the following code for your Timer event:
Private Sub Timer1_Timer()
Me.caption = Timer1.Tag ' just for test purposes
End Sub
Then add a standard Module and paste the following code into it. When
you run the project and click into your MSFlexGrid (Enabled set to
True as normal) you should find that it responds to all keys in its
normal way except that it does not respond at all to the PageUp or
PageDown keys (although, as explained above, you can allow it to
respond in its normal way to the PageUp and PageDown keys as well if
you wish). Each time you press down either the PageUp or PageDown key
the Timer1 event will fire. In this simple example that event merely
reports to keypress in the Form's Caption just for test purposes, and
any code you wish to execute when either of those keys are pressed
should be entered into the Timer event. One other thing, I'm in quite
a rush at the moment and so I've made only the essential modifications
to my "stock" code for doing these sort of things and at the moment
I've not had time to add the code to check the Ctrl key, so the code
as it stands responds to the PageUp and PageDown keys whether the Ctrl
key is held down or not. That extra function is quite easy to add
though and I'm fairly sure you will be able to do it yourself. Post
again if you have any problems with it. (Module code as below):
Mike
Option Explicit
Private Declare Function SetWindowsHookEx Lib "user32" _
Alias "SetWindowsHookExA" (ByVal idHook As Long, _
ByVal lpfn As Long, ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long
Private Declare Function CallNextHookEx Lib "user32" _
(ByVal hHook As Long, ByVal ncode As Long, _
ByVal wParam As Long, lParam As Any) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" _
(ByVal hHook As Long) As Long
Private Const WH_KEYBOARD As Long = 2
Private Hook As Long, tMessage As Timer
Public Sub HookKeyboard(t1 As Timer)
Set tMessage = t1
Hook = SetWindowsHookEx(WH_KEYBOARD, _
AddressOf KeyboardProc, App.hInstance, App.ThreadID)
End Sub
Public Sub UnHookKeyboard()
UnhookWindowsHookEx Hook
End Sub
Public Function KeyboardProc(ByVal ncode As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Dim keyCode As Long
If ncode >= 0 Then
keyCode = wParam And &HFF&
If keyCode = vbKeyPageUp Or keyCode = vbKeyPageDown Then
If (lParam And &H80000000) = 0 Then ' key down
tMessage.Tag = CStr(keyCode)
tMessage.Interval = 10 ' ) one shot
tMessage.Interval = 0 ' ) timer
End If
' Return -1 if we want to kill this key,
' otherwise use CallNextHook
KeyboardProc = -1 ' kill the key
' KeyboardProc = CallNextHookEx(Hook, ncode, wParam, ByVal lParam)
End If
Else
KeyboardProc = CallNextHookEx(Hook, ncode, _
wParam, ByVal lParam)
End If
End Function
.
- References:
- msflexgrid with ctrl-pgup & ctrl-pgdn
- From: rick-paulos@xxxxxxxxx
- Re: msflexgrid with ctrl-pgup & ctrl-pgdn
- From: Rick
- msflexgrid with ctrl-pgup & ctrl-pgdn
- Prev by Date: Re: msflexgrid with ctrl-pgup & ctrl-pgdn
- Next by Date: Re: Windows registry values for Product Name
- Previous by thread: Re: msflexgrid with ctrl-pgup & ctrl-pgdn
- Next by thread: Re: msflexgrid with ctrl-pgup & ctrl-pgdn
- Index(es):
Relevant Pages
|