Author: Richard Winston
Complex forms can use up a lot of the Windows resources. This article describes a
method for reducing the drain on the Windows resources.
Answer:
In my application there is a form with lots of components on it; 1047 components to
be exact. In my development environment, WindowsNT, this did not cause any
problems but under Windows 98, my application would crash if a user tried to create
a second instance of this form. The problem was that in Windows 98, there are a
limited number of Windows resources and one instance of my form used 42% of the
Windows resources. With the operating system already using 20% of the resources,
there weren't enough resources left to create a second instance of the form.
In researching this problem I came across a thread in alt.comp.lang.borland-delphi
by Ken Phipps, Bruce Roberts, and M.H. Avegaart that gave most of a solution to the
problem. The thread extended from Jan. 13, 2001 to Jan. 16, 2001. There is also
an article on the Borland web site that gives some related information
(TI1375D.txt;http://community.borland.com/article/0,1410,16375,00.html).
The following is the solution I implemented in my program. It solved my problem.
First, I created the ConserveResourcesUnit shown below. I called FreeFormResources
in the OnCreate event handler of each form that had a TPageControl. I called
FreePageControlResources in the OnChange event handler of each TPageControl. I
could have gone further and made a component that did the same thing after the page
control was created and when the ActivePage was changed but it didn't seem worth
the effort. I could also have called FreePageControlResources when the ActivePage
of a TPageControl was changed programatically but I haven't gotten around to that
yet. Another option would have been to redesign the form to use fewer TWinControls
but that would have been a lot of effort and would have created other problems.
There is one tricky bit. If you have a TPageControl on a tab of another
TPageControl and you want to set the TabVisible property of one of the tabs on the
former TPageControl you may need to call HandleNeeded for all the tabs on the
former TPageControl before setting the TabVisible property. You can call
FreePageControlResources afterwards to free-up resources. If you don't do this, an
error can occur in the VCL when you try to set the TabVisible property.
If you use a TTabbedNotebook rather than a TPageControl, see the article on the
Borland web site cited above.
1 unit ConserveResourcesUnit;
2
3 interface
4
5 uses Windows, Classes, Controls, Forms, comctrls;
6
7 procedure FreePageControlResources(const APageControl: TPageControl;
8 const FormHandle: HWND);
9
10 procedure FreeFormResources(const AForm: TForm);
11
12 implementation
13
14 type
15 TMyWinControl = class(TWinControl);
16
17 procedure FreePageControlResources(const APageControl: TPageControl;
18 const FormHandle: HWND);
19 var
20 Index: integer;
21 begin
22 // LockWindowUpdate prevents any drawing in a given window}
23 LockWindowUpdate(FormHandle);
24 with APageControl do
25 begin
26 for Index := 0 to PageCount - 1 do
27 begin
28 // DestroyHandle is protected so a typecast is required
29 // to expose it.
30 // Usually, the handles will be automatically recreated when needed.
31 // However, in setting the TabVisible property, they may not be recreated
32 // without a direct call to HandleNeeded.
33 if Pages[Index] <> ActivePage then
34 TMyWinControl(Pages[Index]).DestroyHandle;
35 end;
36 end;
37 {Release the Lock on the Form so any Form drawing can work}
38 LockWindowUpdate(0);
39 end;
40
41 procedure FreeFormResources(const AForm: TForm);
42 var
43 AComponent: TComponent;
44 Index: integer;
45 begin
46 for Index := 0 to AForm.ComponentCount - 1 do
47 begin
48 AComponent := AForm.Components[Index];
49 if AComponent is TPageControl then
50 begin
51 FreePageControlResources(TPageControl(AComponent), AForm.Handle);
52 end;
53 end;
54 end;
55
56 end.
|