Page 1 of 2 12 LastLast
Results 1 to 15 of 18
  1. #1
    Join Date
    Sep 2006
    Posts
    11

    Unhappy Unanswered: User Keystrokes getting missed

    We have a data entry front end built originally in Access 2000 with a SQL Server 2000 back end. It was converted to Access XP with no problems. However when we converted it to Access 2003 we started seeing missing keystrokes in option groups if the user types really fast. Most of our data entry personal have been doing this for quite a while so they are very fast on the 10-key.

    The way that we had things coded during the Form_KeyPress sub was depending on the option group we would read the KeyAscii code and subtract 48 from it and use the resulting number to check the appropriate radio button then tab to the next field.

    Here is a code sample:

    Dim ctl As Control
    Set ctl = Screen.ActiveControl
    If ctl.Name = "8k.8 Other" Then
    If KeyAscii > 48 And KeyAscii < 51 Then '1 or 2
    ctl.Value = KeyAscii - 48
    SendKeys "{TAB}"
    End If
    End If


    Does anyone know why this would work fine in Access 2000-2002 and not in 2003. Nothing has changed code wise but the functionality is very irritating and is slowing down our users quite a bit.

    Thank You,
    Michael

  2. #2
    Join Date
    Mar 2003
    Location
    The Bottom of The Barrel
    Posts
    6,102
    Provided Answers: 1
    What's KeyAscii? Where does that get set?

    This looks pretty inefficient. If you only want to trap say a keypress event of one specific control, you should be placing your code in that specific controls event handler as opposed to instantiating a new generic control object and evaluating it each time a key is pressed.
    oh yeah... documentation... I have heard of that.

    *** What Do You Want In The MS Access Forum? ***

  3. #3
    Join Date
    Sep 2006
    Posts
    11
    KeyAscii is passed into the sub from the form.

    Here is sub header:

    Private Sub Form_KeyPress(KeyAscii As Integer)

    This all legacy code that I didn't write but I have to maintain and I am out of my comfort zone. I normaly use VB.NET. I would like to take the time to rewrite this whole app in VB.NET but I have been told by my boss to leave it as it is but convert it to the current Access version.

    The code snippet is a simplified version of a much more convulated nested if - else statement. This handels the various radio button group sizes from 2 to 9 options.

    Any advice is apreciated,
    Michael

  4. #4
    Join Date
    Mar 2003
    Location
    The Bottom of The Barrel
    Posts
    6,102
    Provided Answers: 1
    I think it's just flat inefficient code that needs a re-write. Dynamically loading objects and using sendkeys were setfocus could come into play is just plain slow. I'm not sure what the overhead difference is between 2k3 and older versions, but I wouldn't be surprised if it's a little bulkier.

    Go ahead and post the general gyst of the code here and we can come up with some more elegant and efficient solutions for you.
    oh yeah... documentation... I have heard of that.

    *** What Do You Want In The MS Access Forum? ***

  5. #5
    Join Date
    Sep 2006
    Posts
    11
    Here you go, thanks for the help...

    Private Sub Form_KeyPress(KeyAscii As Integer)
    On Error GoTo Err_Form_KeyPress

    Dim ctl As Control

    Set ctl = Screen.ActiveControl

    If ctl.Name = "Question 7" Or _
    ctl.Name = "Question 10b" Or _
    ctl.Name = "Question 10b.2.1" Or _
    ctl.Name = "Question 10b.2.2" Or _
    ctl.Name = "Question 10b.2.3" Or _
    ctl.Name = "Question 10b.2.4" Or _
    ctl.Name = "Question 12b " Or _
    ctl.Name = "Question 13" Or _
    ctl.Name = "Question 14" Or _
    ctl.Name = "Question 15" Or _
    ctl.Name = "Question 16" Then
    If KeyAscii > 48 And KeyAscii < 51 Then '1 or 2
    ctl.Value = KeyAscii - 48
    SendKeys "{TAB}"
    End If
    ElseIf ctl.Name = "Question 8" Or _
    ctl.Name = "Question 9" Or _
    ctl.Name = "Question 10c" Or _
    ctl.Name = "Question 12e" Then
    If KeyAscii > 48 And KeyAscii < 52 Then '1,2 or 3
    ctl.Value = KeyAscii - 48
    SendKeys "{TAB}"
    End If
    ElseIf ctl.Name = "Question 10" Or _
    ctl.Name = "Question 11" Or _
    ctl.Name = "Question 12" Or _
    ctl.Name = "Question 12c" Or _
    ctl.Name = "Question 11c" Then
    If KeyAscii > 48 And KeyAscii < 53 Then '1,2,3 or 4
    ctl.Value = KeyAscii - 48
    SendKeys "{TAB}"
    End If
    ElseIf ctl.Name = "Question 11b" Then
    If KeyAscii > 48 And KeyAscii < 55 Then '1,2,3,4,5 or 6
    ctl.Value = KeyAscii - 48
    SendKeys "{TAB}"
    End If
    ElseIf ctl.Name = "Question 12d" Then
    If KeyAscii > 48 And KeyAscii < 57 Then '1,2,3,4,5,6,7 or 8
    ctl.Value = KeyAscii - 48
    SendKeys "{TAB}"
    End If
    End If

    Exit_Form_KeyPress:
    Exit Sub

    Err_Form_KeyPress:
    MsgBox "Error in module Form_KeyPress : " & Err.Description
    Resume Exit_Form_KeyPress

    End Sub

  6. #6
    Join Date
    Sep 2006
    Posts
    11
    There are two other keyxxx subs and here they are...

    Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
    On Error GoTo Err_Form_KeyDown

    Dim pgPages As Pages

    Select Case KeyCode

    Case vbKeyDown 'move to next control
    KeyCode = 0
    SendKeys "{TAB}"
    Case vbKeyUp 'move to previous control
    KeyCode = 0
    SendKeys "+{TAB}"
    Case vbKeyPageDown
    KeyCode = 0 'cancel PageDown key
    Case vbKeyPageUp
    KeyCode = 0 'cancel PageUp key
    End Select

    Exit_Form_KeyDown:
    Exit Sub

    Err_Form_KeyDown:
    MsgBox ("Error in module Form_KeyDown : " & Err.Description)
    Resume Exit_Form_KeyDown

    End Sub

    Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)

    Dim ShiftDown As Boolean
    Dim CtrlDown As Boolean

    CtrlDown = (Shift And acCtrlMask) > 0

    If CtrlDown And KeyCode = vbKey0 Then
    Screen.ActiveControl.Value = Null 'Clear Radio Buttons
    End If

    End Sub

  7. #7
    Join Date
    Mar 2003
    Location
    The Bottom of The Barrel
    Posts
    6,102
    Provided Answers: 1
    This is on keypress for the entire form?

    Here's how I would redo this:

    Make use of the "Tag" property in each of your controls. Tag is an arbitrary property that you can put whatever value you want into it. In this case, I would use it to store an integer representing control category id.

    Next I would use only a single statement to set your ctl.Value, but I would make the range you're using dynamic based on control category id.

    Eg:
    Code:
    Dim ctl As Control
    Dim iSubVal As Integer
    
    Set ctl = Screen.ActiveControl
    
    Select Case ctl.Tag
       Case 1: iSubVal = 51
       Case 2: iSubVal = 52
       Case 3: iSubVal = 53
       Case 4: iSubVal = 55
       Case 5: iSubVal = 57
    End Select
    
    If KeyAscii > 48 And KeyAscii < iSubVal Then
       ctl.Value = KeyAscii - 48
       SendKeys "{TAB}"
    End If
    If you really want to go for the gusto, you could create that as a sub that accepts a control as an argument, then call the sub from each control effected. If you do that, you could also pass in which control is supposed to be selected next, which gives you a performance boost by avoiding send keys:

    Code:
    Private EvalCtl (ByRef Ctl As Control, ByVal targetCtl As String)
    'code up to last bit goes here
    If KeyAscii > 48 And KeyAscii < iSubVal Then
       ctl.Value = KeyAscii - 48
       me.controls(targetCtl).SetFocus
    End If
    oh yeah... documentation... I have heard of that.

    *** What Do You Want In The MS Access Forum? ***

  8. #8
    Join Date
    Sep 2006
    Posts
    11
    Quote Originally Posted by Teddy
    This is on keypress for the entire form?
    Yes the "key" events are on the form level. They are not avaliable at the control level.

    Quote Originally Posted by Teddy

    Here's how I would redo this:

    Make use of the "Tag" property in each of your controls. Tag is an arbitrary property that you can put whatever value you want into it. In this case, I would use it to store an integer representing control category id.

    Next I would use only a single statement to set your ctl.Value, but I would make the range you're using dynamic based on control category id.

    Eg:
    Code:
    Dim ctl As Control
    Dim iSubVal As Integer
    
    Set ctl = Screen.ActiveControl
    
    Select Case ctl.Tag
       Case 1: iSubVal = 51
       Case 2: iSubVal = 52
       Case 3: iSubVal = 53
       Case 4: iSubVal = 55
       Case 5: iSubVal = 57
    End Select
    
    If KeyAscii > 48 And KeyAscii < iSubVal Then
       ctl.Value = KeyAscii - 48
       SendKeys "{TAB}"
    End If
    I assume that I would need to set this iSubValue Tag in the control properties?


    Quote Originally Posted by Teddy
    If you really want to go for the gusto, you could create that as a sub that accepts a control as an argument, then call the sub from each control effected. If you do that, you could also pass in which control is supposed to be selected next, which gives you a performance boost by avoiding send keys:

    Code:
    Private EvalCtl (ByRef Ctl As Control, ByVal targetCtl As String)
    'code up to last bit goes here
    If KeyAscii > 48 And KeyAscii < iSubVal Then
       ctl.Value = KeyAscii - 48
       me.controls(targetCtl).SetFocus
    End If
    How would I set the targetCtl property? I was hoping to avoid using the SendKeys command because I read that the command is restricted now in Access 2003.


    Thanks,
    Michael

  9. #9
    Join Date
    Mar 2003
    Location
    The Bottom of The Barrel
    Posts
    6,102
    Provided Answers: 1
    Quote Originally Posted by Kaytrim
    Yes the "key" events are on the form level. They are not avaliable at the control level.
    Say what? You might want to look at that again...

    I assume that I would need to set this iSubValue Tag in the control properties?
    Yup, that's the basic idea. Plow through your controls and decide which ones you want assigned to what actions and plop a number into it's tag property to be used later. iSubValue is just a local variable filled in by the sub evaluating the tag property.

    How would I set the targetCtl property? I was hoping to avoid using the SendKeys command because I read that the command is restricted now in Access 2003.
    In the individual control's keypress event. That's quite a bit more work as you have to specify an event for each control on the form, but it's FAR more efficient come run-time.
    oh yeah... documentation... I have heard of that.

    *** What Do You Want In The MS Access Forum? ***

  10. #10
    Join Date
    Sep 2006
    Posts
    11
    I am using the Microsoft Visual Basic editor that comes with Access. Above the code window there are two comboboxes. The first one is the object and the second one is the event. I choose one of the controls for the object and all I see are the following events.....

    AfterUpdate
    BeforeUpdate
    Click
    DblClick
    Enter
    Exit
    MouseDown
    MouseMove
    MouseUp

  11. #11
    Join Date
    Mar 2003
    Location
    The Bottom of The Barrel
    Posts
    6,102
    Provided Answers: 1
    Well I'm not sure what's going on... I get onkeyup, onkeydown and onkeypress. You may want to have a look at the events available in the form designer as opposed to the VBE.
    oh yeah... documentation... I have heard of that.

    *** What Do You Want In The MS Access Forum? ***

  12. #12
    Join Date
    Sep 2006
    Posts
    11
    I looked at the properties of one of the option group and there are no keyboard events. The option group controls are what recieve the focus not the option buttons. This is because option group controls have the TabStop and TabIndex properties where the option buttons do not. Also keep in mind that there are well over 500 option buttons on each form. That is a lot of events to code and maintain. For maintainability and code simplicity it would be best to use the Form's keyboard events.

  13. #13
    Join Date
    Mar 2003
    Location
    The Bottom of The Barrel
    Posts
    6,102
    Provided Answers: 1
    that's because option groups don't accept keystrokes.

    Combobox <> option group.

    Edit: n/m, I misread your above post.

    Still stand though, option groups don't accept keystrokes, I don't understand how they're toggling options via a keystroke.
    Last edited by Teddy; 09-22-06 at 17:44.
    oh yeah... documentation... I have heard of that.

    *** What Do You Want In The MS Access Forum? ***

  14. #14
    Join Date
    Sep 2006
    Posts
    11
    Events are passed up the chain of parent objects until a handeler is found. If a handeler is not found the event is ignored. In this case the event is the keypress event.

    1. The focus is on the option group by design so this is the object that origonaly sees the keypress event.

    2. Because the option group doesn't handel the keypress it is passed to the form.

    3. At the form the event is handeled and our code resides here. The event code is executed and control is passed back to the user.

    This same event passing logic happens in VB.NET where I do somthing simaler using group boxes filled with radio buttons. In this case the radio buttons have the focus but even though I can write in an event handeler I don't. I let the event pass up to the group box where I grab the events and handel them for the radio buttons.

    By letting the events percolate up the chain where possible you write less code so there is less chance for mistakes and your code is easier to maintain.
    Last edited by Kaytrim; 09-25-06 at 11:26.

  15. #15
    Join Date
    Mar 2003
    Location
    The Bottom of The Barrel
    Posts
    6,102
    Provided Answers: 1
    Uh... that's about as far away from best practice as you can possibly stray...
    oh yeah... documentation... I have heard of that.

    *** What Do You Want In The MS Access Forum? ***

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •