Speed of dynamic control creation

willisgt

Active Member
Licensed User
I've run into a major problem. I've got a program which, on a given form, creates a number of controls dynamically. The program queries an SQLite table and pulls certain records to determine which controls need to be created. The query works fine, and very quickly.

Okay. So I run through all the records returned by the query and start creating controls. For each record, there's one button and two labels. I also add an event to handle the 'click' event from the button.

In all, I'm creating 28 groups of controls, for a total of 84 controls - and it *takes forever* to complete. Five seconds may not sound like a long time, but for this application, it's just totally unacceptable.

So without hard-coding the controls, is there a way to speed this process up? I've shaved a little time off the process, but it's not nearly enough.

The part of the formVisitCat_Show subroutine that does the work (and takes so long) follows:

B4X:
   Do While reader.ReadNextRow = True

      myCat = reader.GetValue(0)
   
      temp = "BUTTONC" & myCat
      AddButton( "formVisitCat", temp,   1,  i,  19, 15, "*" )   ' "(S)"
      Control( temp ).Color = colorPrefs.GetPixel1( 20, kColorPrefsStandardButton )
      Control( temp ).FontColor = colorPrefs.GetPixel1( 20, kColorPrefsStandardButtonFont )
      Control( temp ).FontSize = 7
      Control( temp ).BringToFront

      If AddEventManager( temp, "Click", "startQuestions") = 0 Then
          AddEvent( temp, Click, "startQuestions")
      End If

      temp = "CATC" & myCat
      AddLabel( "formVisitCat", temp,  20, i, 210, 15, myCat)
      Control( temp ).Color = colorPrefs.GetPixel1( 20, kColorPrefsRadioAndCheckbox )
      Control( temp ).FontColor = colorPrefs.GetPixel1( 20, kColorPrefsRadioAndCheckboxFont )

      temp = "STATC" & myCat
      AddLabel( "formVisitCat", temp, 230, i,  90, 15, "Pending")
      Control( temp ).Color = colorPrefs.GetPixel1( 20, kColorPrefsRadioAndCheckbox )
      Control( temp ).FontColor = = colorPrefs.GetPixel1( 20, kColorPrefsRadioAndCheckboxFont )

      gCategoryList = gCategoryList & myCat & ","
                  
      i = i + 15
      
      'SET THE STATUS FOR EACH CATEGORY
      gQuestionCount = 0
      gQuestionList = ""
   
      gQuestionCount       = reader.GetValue(1)
      iHowManyAnswered    = reader.GetValue(2)
   
      'GET THE NUMBER OF ANSWERS FOR THIS CATEGORY
      If gSetCategoryFlag <> true Then Return

      ' set the value of the 'status' field. update visit status if required.

      If iHowManyAnswered = 0 Then
         Control( "STATC" & myCat ).Text = "Pending"
      End If
      
      If iHowManyAnswered > 0 Then
         Control( "STATC" & myCat ).Text = "" & iHowManyAnswered & " of " & gQuestionCount
      End If

      If iHowManyAnswered = gQuestionCount Then
          Control( "STATC" & myCat ).Text = "Complete"
      End If
      
      If gQuestionCount = 0 Then
          Control( "STATC" & myCat ).Text = "Optional"
      End If
      
   Loop

I know someone will ask - AddEventManager checks to see if a given event has already been added to a control with a specific name. Returns 1 or 0.

BTW, this takes about 5 seconds on an AT&T (HTC) 8125 running a 400mhz Samsung CPU. It takes about 0.1 seconds on my desktop running a 2.5 ghz AMD.

The device is running WM5 w/.Net 2.0. (This wouldn't have anything to do with which service packs of .Net I've got installed, would it?)

It's time for this application to launch and I've got to get over this performance issue - so any help at all, as always, is greatly appreciated.

Gary

:sign0163:
 
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
You should use If...Else If...Else If instead of:
B4X:
If iHowManyAnswered = 0 Then
         Control( "STATC" & myCat ).Text = "Pending"
      End If
      
      If iHowManyAnswered > 0 Then
         Control( "STATC" & myCat ).Text = "" & iHowManyAnswered & " of " & gQuestionCount
      End If

      If iHowManyAnswered = gQuestionCount Then
          Control( "STATC" & myCat ).Text = "Complete"
      End If
      
      If gQuestionCount = 0 Then
          Control( "STATC" & myCat ).Text = "Optional"
      End If
GetPixel is a costly method.
You should call it before the loop and save the results in a variable.
 

RandomCoder

Well-Known Member
Licensed User
Longtime User
Have you considered hard coding the controls but setting the visible property to false, then when you run through your query you just show the controls that are required.
This should be a lot faster than adding each control dynamically.

Regards,
RandomCoder.
 

willisgt

Active Member
Licensed User
I have considered doing just that; that approach would impose a limit as to how many options the user has, and so I'm trying to avoid it. But yes, it may come to that.

I woke up this morning about 4 AM and realized that the problem is probably due to the fact that for every control I create dynamically, the program has to allocate a block of memory. That gets expensive when it's done 80 times in a row.

Is there a way to just allocate a block of memory for the program's use, similar to calloc() or malloc() in C? Or would that do any good in this case?
 
Last edited:

agraham

Expert
Licensed User
Longtime User
Is there a way to just allocate a block of memory for the program's use, similar to calloc() or malloc() in C? Or would that do any good in this case?
You can't - at least not in B4PPC native code - but that's not your problem. It is just that B4PPC is not a high performance environment. Nothing is free and the trade off for the ease of use and weak typing is a loss of performance compared to raw code. Erel indicates that the next version will hopefully perform an order of magnitude better which if fully realised on your code would bring the delay down to a (probably) acceptable 500mS or so. Drop him a PM and ask to be put on the beta tester list ( like me ;)! ) if it is not full already.

http://www.b4x.com/forum/showthread.php?t=1233&highlight=beta
 
Top