Author: Jonas Bilinkevicius
I decided to change the way my application saves its form details by using
WriteComponentResFile. Basically, my application allows users to create their own
forms at run-time (but really just let them change the contents of a panel). Using
WriteComponentResFile('Panel.Dfm', MainPanel); doesn't write the buttons or images
held by the panel to the DFM file. All that is saved is the panel info itself.
Answer:
The key is to make the controls the user drops on the panel owned by the panel, not
the form. Here is an example project to show the principle. Note that you need to
register all classes the user can drop so the streaming system knowns how to create
them.
1 unit Unit1;
2
3 interface
4
5 uses
6 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
7 StdCtrls, Menus, ExtCtrls;
8
9 type
10 TForm1 = class(TForm)
11 CloseButton: TButton;
12 Panel1: TPanel;
13 PopupMenu1: TPopupMenu;
14 Button2: TMenuItem;
15 Edit1: TMenuItem;
16 Label2: TMenuItem;
17 SaveButton: TButton;
18 RestoreButton: TButton;
19 procedure CloseButtonClick(Sender: TObject);
20 procedure PopupMenuClick(Sender: TObject);
21 procedure Panel1MouseDown(Sender: TObject; Button: TMouseButton;
22 Shift: TShiftState; X, Y: Integer);
23 procedure SaveButtonClick(Sender: TObject);
24 procedure RestoreButtonClick(Sender: TObject);
25 private
26 { Private declarations }
27 FPopupPosition: TPoint;
28 function Filename: string;
29 procedure CustomButtonClick(Sender: TObject);
30 public
31 { Public declarations }
32 end;
33
34 var
35 Form1: TForm1;
36
37 implementation
38
39 {$R *.DFM}
40
41 procedure TForm1.CloseButtonClick(Sender: TObject);
42 begin
43 Close;
44 end;
45
46 procedure TForm1.PopupMenuClick(Sender: TObject);
47 var
48 ctrl: TControl;
49 S: string;
50 i: Integer;
51 begin
52 case (Sender as TMenuItem).Tag of
53 1:
54 begin
55 ctrl := TButton.Create(panel1);
56 TButton(ctrl).OnClick := CustombuttonClick;
57 end;
58 2: ctrl := TEdit.Create(Panel1);
59 3: ctrl := TLabel.Create(Panel1);
60 else
61 Exit;
62 end;
63 ctrl.Top := FPopupPosition.Y;
64 ctrl.Left := FPopupPOsition.x;
65 ctrl.Parent := panel1;
66 S := ctrl.Classname;
67 Delete(S, 1, 1);
68 i := 1;
69 while panel1.FindComponent(S + IntToStr(i)) <> nil do
70 Inc(i);
71 ctrl.Name := S + IntToStr(i);
72 end;
73
74 procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton;
75 Shift: TShiftState; X, Y: Integer);
76 var
77 p: TPoint;
78 begin
79 if Button <> mbLeft then
80 Exit;
81 FPopupPosition := Point(X, Y);
82 p := (Sender as TPanel).ClientToScreen(FPopupPosition);
83 PopupMenu1.Popup(p.x, p.y);
84 end;
85
86 function TForm1.Filename: string;
87 begin
88 result := ExtractFilePath(ParamStr(0)) + Name + '.DAT';
89 end;
90
91 procedure TForm1.SaveButtonClick(Sender: TObject);
92 var
93 fs: TFileStream;
94 i: Integer;
95 begin
96 fs := TFileStream.Create(filename, fmCreate);
97 try
98 fs.WriteComponent(panel1);
99 finally
100 fs.free
101 end;
102 for i := panel1.ComponentCount - 1 downto 0 do
103 panel1.Components[i].Free;
104 end;
105
106 procedure TForm1.RestoreButtonClick(Sender: TObject);
107 var
108 fs: TFileStream;
109 i: Integer;
110 begin
111 fs := TFileStream.Create(filename, fmOpenread or fmShareDenyWrite);
112 try
113 fs.ReadComponent(panel1);
114 { Note: this will restore all properties of the read objects,
115 with the exception of events. Since the event handlers belong to the form,
116 not the panel, the reader is unable to resolve the method names to
117 method pointers. So we have to reconnect the event here manually. }
118 for i := panel1.ComponentCount - 1 downto 0 do
119 if panel1.Components[i] is TButton then
120 TButton(panel1.Components[i]).OnClick := CustomButtonClick;
121 finally
122 fs.free
123 end;
124 end;
125
126 procedure TForm1.CustomButtonClick(Sender: TObject);
127 begin
128 ShowMessage((Sender as TButton).Name);
129 end;
130
131 initialization
132 RegisterClasses([TButton, TEdit, TLabel]);
133 end.
134
135 ------------------------------------------------------------------------------------
136 ---------
137 object Form1: TForm1
138 Left = 215
139 Top = 109
140 Width = 556
141 Height = 303
142 Caption = 'Form1'
143 Color = clBtnFace
144 Font.Charset = ANSI_CHARSET
145 Font.Color = clWindowText
146 Font.Height = -15
147 Font.Name = 'Arial'
148 Font.Style = []
149 OldCreateOrder = False
150 Scaled = False
151 PixelsPerInch = 120
152 TextHeight = 17
153 object CloseButton: TButton
154 Left = 24
155 Top = 28
156 Width = 75
157 Height = 25
158 Caption = 'Close'
159 TabOrder = 0
160 OnClick = CloseButtonClick
161 end
162 object Panel1: TPanel
163 Left = 112
164 Top = 24
165 Width = 421
166 Height = 237
167 Caption = 'Click me!'
168 TabOrder = 1
169 OnMouseDown = Panel1MouseDown
170 end
171 object SaveButton: TButton
172 Left = 24
173 Top = 60
174 Width = 75
175 Height = 25
176 Caption = 'Save'
177 TabOrder = 2
178 OnClick = SaveButtonClick
179 end
180 object RestoreButton: TButton
181 Left = 24
182 Top = 92
183 Width = 75
184 Height = 25
185 Caption = 'Restore'
186 TabOrder = 3
187 OnClick = RestoreButtonClick
188 end
189 object PopupMenu1: TPopupMenu
190 Left = 112
191 Top = 4
192 object Button2: TMenuItem
193 Tag = 1
194 Caption = 'Button'
195 OnClick = PopupMenuClick
196 end
197 object Edit1: TMenuItem
198 Tag = 2
199 Caption = 'Edit'
200 OnClick = PopupMenuClick
201 end
202 object Label2: TMenuItem
203 Tag = 3
204 Caption = 'Label'
205 OnClick = PopupMenuClick
206 end
207 end
208 end
209 ------------------------------------------------------------------------------------
210 ---------
|