2

This pertains to embedding ESRI MapControls into Access Database Forms.

I have two access files, split into a frontend and backend. My backend is also a PersonalGeoDatabase that ArcGIS uses to store a feature class for display on a From embedded ESRI map control.

The feature class stores polylines, points, and polygons which are associated with a specific ProjectID.

From the frontend, I have the embedded mapControl which loads the MXD file tied to the backend.

I've got a VB function called CenterPoint, which coincidentally, centers the map envelope around the Project's associated feature class (if it exists) and sets the desired viewing extents. If the feature class for a project doesn't yet exist, it centers the map around the entire region all the projects are contained in, giving a general overview.

So, if that all made sense, and I haven't lost you...

I originally called the CenterPoint sub in the Form_Current Event. This worked, in that it performed all the functionality desired; however, while the CenterPoint function ran, the form was unresponsive, preventing changing to another record until the re-draw had finished. This meant, if you wished to jump through 10 records, you would have to jump 1, wait for re-draw, jump another, wait for re-draw, etc. I sped up the re-draw considerably by optimizing the MXD imagery and layers, but it was still unacceptable.

Next, I tried to establish a delay of a few seconds, before it called the CenterPoint sub by running the following:

Private Sub Form_Current()
    Dim s_Start As single
    Dim s_Delay As single
    s_Start = Timer
    Do While Timer < s_Start + s_Delay
        DoEvents
    Loop

CenterPoint

End Sub

Which gives me the desired responsiveness by using the DoEvents call, meaning I can click multiple records before it tries to re-draw the first time.

Unfortunately, it apparently cache's all the Form_Current calls, and if I skip say, 3 records, wait for the delay to end, and watch the screen, it will re-draw (ie. run CenterPoint) 3 times consecutively.

Even more weird, is it sporadically gives me a division by zero error for the line:

Do While Timer < s_Start + s_Delay

despite having no division in the line.

So, I guess my questions are:

  1. Is there a way to have access only run the form_current call once?
    • If not, is there a way to make sure a user has stayed on the current record for a given time before I call the CenterPoint function?
  2. Is there a way to insulate my less-than comparison from the division by zero error, so at least, even though it will re-draw multiple times, the user can click through records in rapid succession?

Right now, my work around has been to put the CenterPoint sub as a click event for a button on the form, which works, but isn't ideal.

If any of this doesn't make sense, or more information is necessary, please let me know.

Thanks, Spencer

Joel Coehoorn
  • 362,140
  • 107
  • 528
  • 764
slawley
  • 61
  • 1
  • 6

2 Answers2

1

In answer to your questions:
1) Form_ Current will always run whenever you switch records. No choice. So the next best option is to move the call to CenterPoint to another event. I would use the form timer event, and reset the timer every time you go through Form_ Current, when the timer runs out, it will fire CenterPoint off.

Private Sub Form_Current()
    Me.TimerInterval = 10000
End Sub

Private Sub Form_Timer()
    CenterPoint
End Sub

2) If you are using the form timer event, you probably don't need this code any more; however,

Private Sub Form_Current()
Dim l_Start As long 
Dim l_Delay As long 
Dim l_endTime As long 'or integers - time is returning the number of seconds 
                      'since midnight, not a real... this may be the source 
                      'of your problem

    l_Delay = 1000 ' I didn't see you set s_Delay any where
    l_Start = Timer
    l_endTime = l_Start + l_Delay 'lets do the calculation only once.

'This might break down if the user switch records just before midnight
'(never ending loop)
'    Do While Timer < l_endTime 
'        DoEvents
'    Loop

    'Instead I would do this
    Do While (Timer <= l_endTime) _
                and (l_start <= timer)
        DoEvents
    Loop

    CenterPoint

End Sub
BIBD
  • 14,299
  • 24
  • 78
  • 130
0

Another possibility would be to keep the call in the OnCurrent event, but use a time flag outside the OnCurrent to determine whether or not to call the subroutine.

  Static s_Start As Single
  Dim s_Delay As Single

  If s_Start = 0 Then
     s_Start = Timer
  End If
  If Timer > s_Start + s_Delay
     Call CenterPoint
     s_Start = 0
  End If

Now, that's air code, so I may have a mistake or two in it, but the idea is that you run the code only once the delay has expired. And once it's expired, you set the start time back to 0 so that counter will start over again.

The result is that the call to CenterPoint will happen only on those OnCurrent events that happen after your delay has expired.

Joel Coehoorn
  • 362,140
  • 107
  • 528
  • 764
David-W-Fenton
  • 22,262
  • 3
  • 41
  • 55
  • @Joel Coehoorn That is a little sad. David died just last year http://www.davis-andersonfuneralhome.com/obits/obituaries.php/obitID/435707/obit/David-W-Fenton – Fionnuala May 25 '12 at 17:04