tags:

views:

99

answers:

4

I'm stuck with VB6 and I'm using Form.Controls.Add(...) to create a bunch of controls at runtime.

Unfortunately this seems to be a very slow process, with heavy flickering.

Is there any way to speed up the process? Perhaps it's possible to somehow notify VB6 that I'm doing a mass-insert of new controls.

+3  A: 

I've used control arrays for this. Create a single instance of each type of control you're going to need--textbox, label, dropdown list, etc. Set the Index property of each control to 0, (which turns each control into the base control for a control array). Now set the other properties to what makes sense for each type of control in your application. These properties will be applied to each new control as it's created. Be sure that you set the Visible property to False.

Then, add controls at runtime with the Load statement. Position them appropriately, set any unique properties, load your data, etc., then when that's all done sweep through each control array by index and set the Visible property on each control to True. This is fast enough that it avoids the flicker, at least for a reasonable amount of controls. I've handled almost 200 controls this way without flicker.

Also, if/when you need to rebuild the form with new data, rather than destroying the controls with Unload, then recreating new ones, just make them all invisible, and re-use as many as you need. It's much, much faster to tweak the properties for each control this way as opposed to creating them from scratch each time.

True, you do need to manage an index for each control array's length to tell you if you can reuse or need to create a new one, but a couple of helper functions can go a long way toward simplifying the necessary tracking. Something like this:

Set newTextBox = GetNextTextBox

where the GetNextTextBox function handles tracking of the total textbox controls available, and which one is "next" so it can decide whether it can reuse an existing one or has to create a new one.

You may also have functions like, for example, ResetTextBoxes, that makes all of the textboxes invisible and resets the "next available" counter.

JeffK
+4  A: 

You can use a hidden picturebox for the container like this

Set oCtl = Controls.Add("VB.TextBox", "txtMy1", picHidden)

Then you can either show the container which will be as fast as can be or hide the controls and reset container like this

oCtl.Visible = False
Set oCtl.Container = Form1 ' or picHidden.Container

In any case you can reduce flicker by using a hidden container.

wqw
+3  A: 

Disabling the form while creating the controls helps. If it's practical, it will help even more to actually set Visible = False on that form.

Brother Erryn
If you decide to make the form not visible, just be aware that some controls have issues with with this state. One thing we used to do was position the form at negative co-ordinates.
CMH
A: 

I frequently use the API call LockWindowUpdate to disable drawing in a listbox when adding a lot of items. It dramatically speeds up the loading and is simple to declare and use. I imagine it would work just as well for a form. But because Ken White pointed me to this article that explains why using LockWindowUpdate is wrong I started modifying my code to use SendMessage instead. So far it seems to work as well in the program as LockWindowUpdate does.

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Const WM_SETREDRAW = &HB

Private Sub AddMyControls()

    ' The SendMessage function returns 0 for this message if successful,
    ' instead of using Call assign the return to a variable to check the success

    Call SendMesssage(Me.hwnd, WM_SETREDRAW, False, 0) ' prevent re-drawing while adding controls
    ' .... add controls

    ' It might be nice to know if the function was successful here
    ' or re-drawing might not be re-enabled and the user would wonder what's up
    Call SendMesssage(Me.hwnd, WM_SETREDRAW, True, 0)  ' re-enable drawing

End Sub
Beaner
This is the *last* thing you should think of doing. http://blogs.msdn.com/oldnewthing/archive/2007/02/22/1742084.aspx
Ken White
Okay, something I didn't know before. Now I need to replace my LockWindowUpdate with SendMessage and compare the functionality.
Beaner