6 Replies Latest reply on Nov 19, 2012 4:09 PM by andreas

    Circular referencing Trend TimeRangeChange event?

    aarloe

      Hello, first time poster to the vCampus, (relatively) new VBA Scriptor in PB. I was wondering if it might be possible to expand the TimeRangeChange demo that appears in the Advanced Processbook Scripting CBT to include updating the time ranges for ALL trends on a display whenever ANY trend's time range is updated? I've tried this on my own with say, 3 trends, and whenever I zoom in on one trend, PB crashes. It kind of works when using only 2 trends, but is still noticebly slower than just one trend.

      For example, the code in the demo shows this:

      Private Sub Trend_TimeRangeChange(ByVal StartTime As String, ByVal EndTime As String)
          Trend2.SetTimeRange StartTime, EndTime
      End Sub

       

      which updates the time range of the second trend on the display whenever the first trend's time range is changed (i.e. by zooming anywhere). What I'd like to do is this:

      Private Sub Trend1_TimeRangeChange(ByVal StartTime As String, ByVal EndTime As String)
          Trend2.SetTimeRange StartTime, EndTime
          Trend3.SetTimeRange StartTime, EndTime
      End Sub

      Private Sub Trend2_TimeRangeChange(ByVal StartTime As String, ByVal EndTime As String)
          Trend1.SetTimeRange StartTime, EndTime
          Trend3.SetTimeRange StartTime, EndTime
      End Sub

      Private Sub Trend3_TimeRangeChange(ByVal StartTime As String, ByVal EndTime As String)
          Trend1.SetTimeRange StartTime, EndTime
          Trend2.SetTimeRange StartTime, EndTime
      End Sub

      But I think I'm just creating an infinite loop, such that whenever I zoom in on Trend1, Trend2 & Trend3's time ranges are changed, which causes them to execute the code, which changes the time range of Trend1, and the cycle repeats indefinately until I force quit PB.

       

      Any suggestions?

        • Re: Circular referencing Trend TimeRangeChange event?

          Hi aarloe,

           

          There is no EnableEvents property in ProcessBook so you need to build your own.  A simple example using your code would be to have a module level Boolean variable that is set whether events should be processed - this does mean you need to add a check inside your events.  In your example you could do something along the lines of:

          Private NoEvents As Boolean ' When VBA resets, NoEvents defaults to False

          Private Sub Trend1_TimeRangeChange(ByVal StartTime As String, ByVal EndTime As String)
              If NoEvents Then Exit Sub
              NoEvents = True

              Trend2.SetTimeRange StartTime, EndTime
              Trend3.SetTimeRange StartTime, EndTime

              NoEvents = False
          End Sub

          Private Sub Trend2_TimeRangeChange(ByVal StartTime As String, ByVal EndTime As String)
              If NoEvents Then Exit Sub
              NoEvents = True

              Trend1.SetTimeRange StartTime, EndTime
              Trend3.SetTimeRange StartTime, EndTime

              NoEvents = False
          End Sub

          Private Sub Trend3_TimeRangeChange(ByVal StartTime As String, ByVal EndTime As String)
              If NoEvents Then Exit Sub
              NoEvents = True

              Trend1.SetTimeRange StartTime, EndTime
              Trend2.SetTimeRange StartTime, EndTime

              NoEvents = False
          End Sub

            • Re: Circular referencing Trend TimeRangeChange event?

              Since we all have a part of us that's lazy (admittedly this part may be bigger for some individuals, but that's a different topic ), I started to think: 'hey, how could I automate this and not have to copy/paste that procedure every time, making sure all the trends are being updated?'

               

              And I came up with what follows - feel free to use (and criticize):

               

              First you declare that 'NoEvents' variable as per Rhys' suggestion:

              Private NoEvents As Boolean ' When VBA resets, NoEvents defaults to False]

               

              Then you write a short procedure that updates all the trend symbols on your display:

              Private Sub UpdateTimeRangeForAllTrends(StartTime As String, EndTime As String)
                  Dim oSymbol As Symbol
                  Dim oTrend As trend

                  For Each oSymbol In ThisDisplay.Symbols
                      If oSymbol.Type = pbSymbolTrend Then
                          Set oTrend = CVar(oSymbol)
                          oTrend.SetTimeRange StartTime, EndTime
                      End If
                  Next
              End Sub

               

              And now you simply make sure that any new Trend symbol that is added to the Display will call that procedure when its time range is changed. For this you use the Display's AfterSymbolAdded event and the VBA Environment objects to add code that invokes the 'UpdateTimeRangeForAllTrends' method.

               

              Note that in order to do this you will need to add a reference (Tools > Refefences) to 'Microsoft Visual Basic for Applications Extensibility x.y' (mine is 5.3).

               

              Then the code looks like this:

              Private Sub Display_AfterSymbolAdded(ByVal pSymbol As Symbol)
                  If pSymbol.Type <> pbSymbolTrend Then Exit Sub

                  Dim thisCode As VBIDE.CodeModule
                  Set thisCode = Application.VBE.VBProjects("VBAProject").VBComponents("ThisDisplay").CodeModule

                  thisCode.InsertLines thisCode.CountOfLines + 1, _
                      "Private Sub " & pSymbol.Name & "_TimeRangeChange(ByVal StartTime As String, ByVal EndTime As String)" & vbNewLine & _
                      "    If NoEvents Then Exit Sub" & vbNewLine & _
                      "    NoEvents = True" & vbNewLine & _
                      "    UpdateTimeRangeForAllTrends StartTime, EndTime" & vbNewLine & _
                      "    NoEvents = False" & vbNewLine & _
                      "End Sub"

              End Sub

               

              And of course you don't want to leave garbage code in case you delete that trend... so you take advantage of the Display's BeforeSymbolDelete event to clean it up:

              Private Sub Display_BeforeSymbolDelete(ByVal pSymbol As Symbol, CancelDefault As Boolean)
                  If pSymbol.Type <> pbSymbolTrend Then Exit Sub

                  Dim thisCode As VBIDE.CodeModule
                  Set thisCode = Application.VBE.VBProjects("VBAProject").VBComponents("ThisDisplay").CodeModule

                  Dim iLine As Integer
                  For iLine = 1 To thisCode.CountOfLines
                      If thisCode.Lines(iLine, 1) = "Private Sub " & pSymbol.Name & "_TimeRangeChange(ByVal StartTime As String, ByVal EndTime As String)" Then
                          thisCode.DeleteLines iLine, 6
                      End If
                  Next
              End Sub

               

              As a result, every time you add a Trend symbol to your display, the following is added at the very bottom of your code (where ?? is the number ProcessBook gave to your trend symbol):

              Private Sub Trend??_TimeRangeChange(ByVal StartTime As String, ByVal EndTime As String
                  If NoEvents Then Exit Sub
                  NoEvents = True
                  UpdateTimeRangeForAllTrends StartTime, EndTime
                  NoEvents = False
              End Sub

               

              Note that renaming of Trend symbols is not being supported with this code, meaning you'll have to edit the Trend's TimeRangeChange event manually in case you rename one.

               

              Note that I attached a display that contains the code to this post.

               

              Hope this helps!

                • Re: Circular referencing Trend TimeRangeChange event?
                  Aantje

                  Hi Steve!

                   

                  On more question.

                   

                  I've implemented your code into a processbook display, and it works fine. But there is one little which I would to to solve.

                   

                  In my trends, my default time settings are "*-8h", "*+8h" (yes, I'm looking into the future :-))

                   

                  And without this code, there is a vertical dotted line at "*" in the trend. But when I implement this code, the dotted line disappear (because I'm resetting the start- and endtime, I think).

                   

                  So is there a way to get this vertical dotted line back into my trends?

                   

                  Greetz, Arie

                    • Re: Circular referencing Trend TimeRangeChange event?
                      andreas

                      Arie - I assume you run into the issue when you zoom´, because the code will set absolute times as you already suspect. You could 'translate' the absolute time to relative:

                       
                      Private Sub UpdateTimeRangeForAllTrends(StartTime As String, EndTime As String)
                          Dim oSymbol As Symbol
                          Dim oTrend As trend
                      
                          Dim dEndTime As Date
                          On Error Resume Next
                          dEndTime = EndTime
                          
                          If dEndTime > Now() Then
                              Dim dDiff As String
                              dDiff = DateDiff("s", Now(), EndTime)
                              EndTime = "*+" & dDiff & "s"
                          End If
                          
                          For Each oSymbol In ThisDisplay.Symbols
                              If oSymbol.Type = pbSymbolTrend Then
                                  Set oTrend = CVar(oSymbol)
                                  oTrend.SetTimeRange StartTime, EndTime
                              End If
                          Next
                      End Sub
                      

                       

                        • Re: Circular referencing Trend TimeRangeChange event?
                          Aantje

                          Hi Andreas,

                           

                          I just noticed that I have a problem with your code :-(

                           

                          When I click the revert button (after zooming, or going back or forwards in time), all 3 trend jump to my start setting (*-8h, *+8h). So far so good.

                           

                          But then all 3 trends don't update anymore....

                           

                          So I implemented Rhys' coding, as written above.

                           

                          Reverting (after zooming etc.) works fine for a 3 trends, but only the trend in which I clicked the Revert button, stays alive. This trend updates every 5 seconds or so, but the other two trends are "dead".

                           

                          So I have to make all 3 trends alive, to keep the trends in sync.

                           

                          Any idea?

                           

                          (btw: my 3 trends are all filled with dataset, which I dynamiclly build over VBA. Don't know if this has anything to do with it?

                           

                          Greetings, Arie