Link to home
Start Free TrialLog in
Avatar of GWitek
GWitekFlag for United States of America

asked on

Set focus, without calling the tab change event?

I'm using Access 2003
I have a form with 8 tabs on it.
If a user tries to move to another tab I have code in the Private Sub TabCtl_Change() that calls a function to make sure all the fields were filled out correctly. The function checks the the form, if it finds a problem it displays an error message and then sets the focus to checkbox or text box in question.  The problem is when it does this (sets focus) it jumps to the TabCtl_Change() right then and there.  This causes the code to step through the function again which causes the error to display twice.  How can I get around this?

The "Print" button on my form calls the same function, however it works fine because I never changed tabs in the first place.

Hopefully that makes sense, you might have to ready it a couple of times.

TIA,
Avatar of Bill Ross
Bill Ross
Flag of United States of America image

Hi  GW,

You cannot do that.  

As you've found the tab control change events fires once when the tab control is changed and again when it is changed back.  

Some ideas:
 1. Add your validation function to the first field in the tab order of each tab in the tab control to tet to see if the priorr tabe was filled out and then go to that tab.
 2. Change your function to only enable the other tabs when the data is correct.

Regards,

Bill
control to tet to see if the priorr tabe was filled
S/B control to test to see if the prior tab was filled

Have a module level variable declared, called say  AmIDirty and set to False by default.  When ever ANY field changes set AmIDirty to True.
Now in TabCtl_Change() first check if AmIDirty is False and if it is exit the function. If AmIDirty is TRUE then do your checks and then set AmIDirty to False before setting focus again to the field you want to.

Easy :D
Avatar of Jim Dettman (EE MVE)
<<How can I get around this?>>

 Give this a go.  Think it will do the job:

 Use a form level variable to protect your validation code from executing multiple times for the same tab.

Dim intLastPage as Integer

In  OnChange of tab control:
      If Me.<tabControl>.page <> intLastPage
        ' User tried to move to a new page, check the fields.
        intRet = ValidateFunction()
        If intRet = True
          ' We are going to move to a new page, so intLastPage  
            intLastPage = Me.<tabControl>.Page
        Else
          ' We have moved back to the page because validation failed.
          ' Nothing to do
        End If
     End If

JimD.
Slight correction:

      If Me.<tabControl>  <> intLastPage
        ' User tried to move to a new page, check the fields.
        intRet = ValidateFunction()
        If intRet = True
          ' We are going to move to a new page, so update intLastPage  
            intLastPage = Me.<tabControl>
        Else
          ' We have moved back to the page because validation failed.
          ' Nothing to do
        End If
     End If

  No "page" property, silly me.

JimD.
SOLUTION
Avatar of Rey Obrero (Capricorn1)
Rey Obrero (Capricorn1)
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of GWitek

ASKER

JDettman,
I think we're close. But I'm drawing a blank.

Through out the function I have "Exit Function", which is used when I find something that isn't right on the form because I don't want to continue checking.

How do I Exit Function and send a return code with it?
I am not sure what function you are referring to (the Tab_Change event is a Sub), but it looks like you need to set your function to return a value.

Also, it is a good idea to set up an error handler and use GoTo ErrorHandlerExit instead of Exit Function, so any necessary closing actions can be taken before exiting.
If the function is checking for valid entries in the page controls, then set it to return (say) blnValid As Boolean.  Set blnValid to True if all checks are passed, or to False if one fails.  Then set the function itself to blnValid.
<<How do I Exit Function and send a return code with it? >>

 As Helen has said, you need to structure it properly.   A well strucutred procedure should have only one exit point.  There are a couple of ways to do that, but it might look something like this:

Function ValidateFields() as Boolean

  Dim strUserMessage as string

  On Error Goto Error_ValidateFields

  ValidateFields = True

  'First check
  If Me.<some control> = "" then
      strUserMessage = strUserMessage & "Some control is required" & vbCrLF
  End If

  'Second check
  If Me.<some control2> = "" then
      strUserMessage = strUserMessage & "Some control2 is required" & vbCrLF
  End If

  ' All done with checks, tell user what went wrong if errors were found.
  If strUserMessage<>"" then
     strUserMessage = strUserMessage  & vbCrLf &  "You must correct these errors before proceeding".
     Msgbox strUserMessage, vbOKOnly + vbExclamation
     ValidateFields = False
  End If

Exit_ValidateFields:
   ' Clean up
   On Error Resume Next
   
    Exit Function

Error_ValidateFields:
     Msgbox "Unexpected error in ValidateFields"
     ValidateFields = False
     Resume Exit_ValidateFields

End Function


   This checks all conditions and then reports to the user.   Some procedures do it the other way; stop on each error found and set focus to the control that caused the error.    This works well when there are few errors, but generally I find most like to see all errors so they can fix them in one shot.

HTH,
JimD.
Avatar of GWitek

ASKER

Examples are looking good and helping. However, no where do I see any of the code setting focus to the tab in error.

The problem is that as soon as the code in the ValidateTabs() function sets the focus to something on the form, the code jumps back to the Private Sub TabCtl0_Change () and reruns the function.
Avatar of GWitek

ASKER

<< This checks all conditions and then reports to the user.   Some procedures do it the other way; stop on each error found and set focus to the control that caused the error.    This works well when there are few errors, but generally I find most like to see all errors so they can fix them in one shot. >>

Sadly enough, my users need quite a bit of hand holding and I'd like to use this method, but can't for the non-intuitive users.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
GWitek,

did you test the sample db at http:#a34879343
Hi again GW,

There are some good solutions here but as I said early on, you should probably review what you are trying to do and change where the test fires.  Perhaps just move the data test to the before update event of the record.  That way it will always check the data before it is saved and you're sure the data is correct regardless of which tab the mistake is on.

Regards,

Bill
Avatar of GWitek

ASKER

I'm going to test out some of these options and get back to you guys.
Avatar of GWitek

ASKER

Just FYI the hyperlink above that says "Standard Comment Box" is dead. IE8
Additionally, I'd like to give some points aways. I was able to get this to work using a few solutions above.