Delphi Win32: accelerating dynamically created controls (parent property)

We have a graphical interface of several frames that dynamically create their contents. Each frame creates panels, labels, changes, comboboxes, etc., which will be used as input fields. This works very well, and we also plan to provide each frame with its contents in separate streams.

However, there is one big problem: it is rather slow! Creating controls does not take time, but setting the Parent property seems very time-consuming.

I tried several ways to speed things up, but no luck. I tried Enabled = False, Visible = False, DisableAlign, LockWindowUpdate, WM_SETREDRAW ... but nothing affects the lengthy process of setting the control parent.

Even if we use streams, it will take time, since VCL functions must be called in Synchronize.

Is there any other way to speed up the creation and display of controls?

Regards, Magnus

Edit: The GUI does not have any data-dependent components or any events. I just create controls and display them. Using timers, I defined the purpose of the parent controls (AControl.Parent: = AOwner) as part of the time.

Edit 2: As shown in the answer below, the speed issue does not specify the parent element, but the color of the control. When I checked the time when the container was visible, and setting the parent caused the control to paint immediately.

Edit 3: Another part of our dynamic GUI is assigning items to combo boxes. ComboBox.Items.Assign (DataItems), where DataItems has at most three to six elements.

Thanks for taking the time to help me!

+6
user-interface dynamic delphi
source share
8 answers

Do not try to use multiple threads to create controls or to work with VCL in general. In any case, this will not improve speed, but, more importantly, this is a complete no-no with VCL.

Edit:. You should read other questions and answers here in StackOverflow that deal with VCL and multiple threads, but in short: VCL is not thread safe, all access to the controls should be done in the context of the main thread. Therefore, when using multiple threads, you will have to wrap up almost all Synchronize () calls, which actually serialize all threads and slow down.

Itโ€™s best to restructure your user interface so that you donโ€™t need to create it right away. Create all frames on demand only when they are shown for the first time.

Edit 2: Here are some test codes showing that setting the Parent property is not a real problem, but perhaps all controls (with all message processing) are being created.

procedure TForm1.Button1Click(Sender: TObject); var i, j, x, y: integer; Edit: TEdit; Ticks: LongWord; begin Visible := FALSE; DestroyHandle; try for i := 1 to 20 do begin y := 20 + i * 25; for j := 1 to 10 do begin x := (j - 1) * 100; Edit := TEdit.Create(Self); Edit.SetBounds(x, y, 98, 23); Edit.Parent := Self; end; end; finally Ticks := timeGetTime; Visible := TRUE; Caption := IntToStr(timeGetTime - Ticks); end; end; 

The code dynamically creates 200 TEdit controls, freeing the handle of the parent form. Creating all these controls and setting their properties takes about 10 milliseconds on my system, but finally, displaying the form (which will create all the windows) takes a few 100 milliseconds. Since this can only be done in the main thread, I doubt that using multiple threads will help you.

+5
source share

I donโ€™t know if this will work, but have you tried to create your forms in .dfm format, and then use the ObjectTextToBinary function to upload .dfm directly to the form. It may or may not work, it's worth exploring.

+2
source share

What do you set for the DisableAlign parameter? Try making DisableAlign on each control that may contain child controls (such as panels). I have seen the result of DisableAlign in huge acceleration for dynamically built forms before.

Edit: Reflecting on this a bit more, my answer was partially speculative. I don't know if the effect of setting DisableAlign will affect the root of the control tree on it or not. I assumed that this is not so, but it is possible. I will need to look at the VCL code. (However, some of the acceleration was true.)

+2
source share

I found this problem some time ago and significantly improved the creation time by simply placing the controls in a temporary frame (i.e., which is not assigned to the form). I believe that slowness depends on each control associated with the parent form (in the end) for many calls like SetBounds, SetVisible, etc. Using a floating frame, you can get this and execute, and then assign a frame to the form that you need.

+2
source share

You can offload the actual data retrieval into the background thread, but the UI stuff should happen in one thread, the main thread. Thus, the actual setting of your frame will occur in the same stream.

Have you tried the Profiler? Your GUI may be too connected, and updating / posting causes a lot of unnecessary events / side effects. Using the profiler, you can get more information about what actually leads to poor performance. This can lead, for example, to a signal that you spent a lot of time just waiting for the database to return, or it may be that each set fires an event that fires another event.

+1
source share

If you are using Dataware controls, make sure you call DisableControls on the TDataSet. It can also cause a lot of reviews.

+1
source share

Another wild assumption: try creating your container (form, panel or frame) using Visible: = false. Then add all the dynamically created controls, and then set Visible: = true

+1
source share

Just a wild assumption: perhaps this helps to establish the parents of the controls in the reverse hierarchical order, i.e. first set the parent of the most deeply nested controls, and then their parents, etc. This may disable some unnecessary updates, because Windows does not yet โ€œknowโ€ about your controls.

0
source share

All Articles