Sign in Join
Wiki copytemporary

LCL Tips/de: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## GUI Anwendung per Code erstellen
22
33Es ist möglich eine [[Overview of Free Pascal and Lazarus/de|GUI Anwendung]] (Graphical User Interface) vollständig durch Pascalcode in Lazarus zu erstellen. Alles, was von der IDE aus möglich ist, ist auch per Code umsetzbar. Die nachfolgenden Beispieldateien für die Programm- und Unitdateien (codegui.lpr und mainform.pas) können Sie als Vorlage verwenden, die Sie anpassen können. Das wichtigste ist, nicht zu vergessen die [[Parent/de|Parent]]-Eigenschaft der Komponenten festzulegen. Die Erstellung von Steuerelementen innerhalb des Formulars erfolgt am besten im Konstruktor des Formulars:
44
55Hauptprogrammdatei:
66
77``` pascal
88program codedgui;
99
1010{$MODE DELPHI}{$H+}
1111
1212uses
1313 Interfaces, Forms, StdCtrls,
1414 MainForm;
1515
1616var
1717 MyForm: TMyForm;
1818begin
1919 Application.Initialize;
2020 Application.CreateForm(TMyForm, MyForm);
2121 Application.Run;
2222end.
2323```
2424
2525Die Unit, die das Formular beinhaltet:
2626
2727``` pascal
2828unit mainform;
2929
3030{$MODE DELPHI}{$H+}
3131
3232interface
3333
3434uses Forms, StdCtrls;
3535
3636type
3737 TMyForm = class(TForm)
3838 public
3939 MyButton: TButton;
4040 procedure ButtonClick(ASender: TObject);
4141 constructor Create(AOwner: TComponent); override;
4242 end;
4343
4444implementation
4545
4646procedure TMyForm.ButtonClick(ASender:TObject);
4747begin
4848 Close;
4949end;
5050
5151constructor TMyForm.Create(AOwner: TComponent);
5252begin
5353 inherited Create(AOwner);
5454 //Hint: FormCreate() is called BEFORE Create() !
5555 //so You can also put this code into FormCreate()
5656 //(This is not the case when creating components ..)
5757
5858 Position := poScreenCenter;
5959 Height := 400;
6060 Width := 400;
6161
6262 VertScrollBar.Visible := False;
6363 HorzScrollBar.Visible := False;
6464
6565 MyButton := TButton.Create(Self);
6666 with MyButton do
6767 begin
6868 Height := 30;
6969 Left := 100;
7070 Top := 100;
7171 Width := 100;
7272 Caption := 'Close';
7373 OnClick := ButtonClick;
7474 Parent := Self;
7575 end;
7676
7777 // Erstellen Sie hier noch weitere Komponenten
7878end;
7979
8080end.
8181```
8282
8383## Bedienelemente manuell erzeugen ohne Overhead
8484
8585### Parent zuletzt setzen
8686
8787**Für Delphianer**: Im Gegensatz zu Delphi erlaubt die LCL beinahe alle Eigenschaften in beliebiger Reihenfolge zu setzen. Zum Beispiel unter Delphi können sie ein Bedienelement nicht ohne a parent positionieren. Die LCL erlaubt dies und dieses Feature kann benutzt werden, den Overhead zu reduzieren.
8888
89-` with TButton.Create(Form1) do begin`\
90-`   // 1. Erzeugen eines button setzt die Vorgabegröße`\
91-`   // 2. Ändern der Position. Keine Randeffekte, weil Parent=nil`\
92-`   SetBounds(10,10,Width,Height);`\
93-`   // 3. Ändern der Größe abhängig vom Thema. Noch nicht, weil Parent=nil`\
94-`   AutoSize:=true;`\
95-`   // 4. Ändern der Größe wegen AutoSize=true. Noch nicht, weil Parent=nil`\
96-`   Caption:='Ok';`\
97-`   // 5. Setzen sie Parent. Jetzt geschieht all das obige, aber in einer einzigen Aktion.`\
98-`   Parent:=Form1;`\
99-` end;`
89+``` pascal
90+ with TButton.Create(Form1) do begin
91+ // 1. Erzeugen eines button setzt die Vorgabegröße
92+ // 2. Ändern der Position. Keine Randeffekte, weil Parent=nil
93+ SetBounds(10,10,Width,Height);
94+ // 3. Ändern der Größe abhängig vom Thema. Noch nicht, weil Parent=nil
95+ AutoSize:=true;
96+ // 4. Ändern der Größe wegen AutoSize=true. Noch nicht, weil Parent=nil
97+ Caption:='Ok';
98+ // 5. Setzen sie Parent. Jetzt geschieht all das obige, aber in einer einzigen Aktion.
99+ Parent:=Form1;
100+ end;
101+```
100102
101103Wenn ein Bedienelement a Parent hat, dann werden alle Eigenschaften unverzüglich wirksam. Ohne a Parent tun viele Eigenschaften nicht mehr, als den Wert zu speichern. Und sobald the Parent gesetzt ist, wird jede Eigenschaft angewendet. Das trifft besonders für grand children zu:
102104
103-` GroupBox1:=TGroupBox.Create(Self);`\
104-` with GroupBox1 do begin`\
105-`   with TButton1.Create(Self) do begin`\
106-`     AutoSize:=true;`\
107-`     Caption:='Click me';`\
108-`     Parent:=GroupBox1;`\
109-`   end;`\
110-`   Parent:=Form1;`\
111-` end;`\
112-` Form1.Show;`
105+``` pascal
106+ GroupBox1:=TGroupBox.Create(Self);
107+ with GroupBox1 do begin
108+ with TButton1.Create(Self) do begin
109+ AutoSize:=true;
110+ Caption:='Click me';
111+ Parent:=GroupBox1;
112+ end;
113+ Parent:=Form1;
114+ end;
115+ Form1.Show;
116+```
113117
114118Autosizing startet nicht bevor jeder parent eingerichtet ist und das Formular sichtbar wird.
115119
116120### Vermeiden sie eine frühe Handle Erzeugung
117121
118122Sobald das Handle eines TWinControl erzeugt ist, ändert jede Änderung einer Eigenschaft the visual thing (called the widget), sogar wenn ein Bedienelement nicht sichtbar ist. Wenn es ein Handle hat, sind Änderungen dennoch aufwändig.
119123
120124### Verwenden sie SetBounds anstelle von Left, Top, Width, Height
121125
122126Anstelle von
123127
124-` with Button1 do begin`\
125-`   Left:=10;`\
126-`   Top:=10;`\
127-`   Width:=100;`\
128-`   Height:=25;`\
129-` end;`
128+``` pascal
129+ with Button1 do begin
130+ Left:=10;
131+ Top:=10;
132+ Width:=100;
133+ Height:=25;
134+ end;
135+```
130136
131137verwenden sie
132138
133-` with Button1 do begin`\
134-`   SetBounds(10,10,100,25);`\
135-` end;`
139+``` pascal
140+ with Button1 do begin
141+ SetBounds(10,10,100,25);
142+ end;
143+```
136144
137145Left, Top, Width, Height rufen SetBounds auf. Und jede Änderung der Position oder Größe ruft die Neuberechnung aller sibling Bedienelemente und eventuell rekursiv die der parent und/oder der grandchild Bedienelemente auf.
138146
139147## DisableAlign / EnableAlign
140148
141149Wenn sie viele Bedienelemente positionieren, ist es eine gute Idee, die Neuberechnungvon all auto sizing, aligning, anchoring zu deaktivieren.
142150
143-` DisableAlign;`\
144-` try`\
145-`   ListBox1.Width:=ClientWidth div 3;`\
146-`   ListBox2.Width:=ClientWidth div 3;`\
147-`   ListBox3.Width:=ClientWidth div 3;`\
148-` finally`\
149-`   EnableAlign;`\
150-` end;`
151+``` pascal
152+ DisableAlign;
153+ try
154+ ListBox1.Width:=ClientWidth div 3;
155+ ListBox2.Width:=ClientWidth div 3;
156+ ListBox3.Width:=ClientWidth div 3;
157+ finally
158+ EnableAlign;
159+ end;
160+```
151161
152162**Anmerkung**: Jeder DisableAlign Aufruf benötigt einen EnableAlign Aufruf. Zum Beispiel wenn sie DisableAlign zweimal aufrufen, müssen sie auch EnableAlign zweimal aufrufen.
153163
154164**Für Delphianer**: Dies funktioniert rekursiv. Das bedeutet, DisableAlign stoppt aligning in allen childs und grand childs.
155165
156166## Ein nicht-rechteckiges Fenster oder Steuerelement erstellen
157167
158168Sie können mit Lazarus recht einfach nicht rechteckige Fenster oder Steuerelemente erstellen. Hierzu können Sie einfach TWinControl.SetShape aufrufen, mit den sichtbaren Bereichen als ein Parameter. Hinweis: dies funktioniert für Fenster und Steuerelemente, wie TCustomForm und TCustomControl, die von TWinControl abgeleitet sind. Sie können LCLIntf-Routine SetWindowRgn aufrufen, die vollständig dem Aufruf der SetShape-Methode entspricht.
159169
160170Mit SetWindowRgn wird der Code wie folgt aussehen:
161171
162172``` pascal
163173uses LCLIntf, LCLType;
164174
165175procedure TForm1.FormCreate(Sender: TObject);
166176var
167177 MyRegion: HRGN;
168178begin
169179 MyRegion := CreateRectRgn(0, 0, 100, 100);
170180 SetWindowRgn(Handle, MyRegion, True);
171181 DeleteObject(MyRegion);
172182end;
173183```
174184
175185Nachfolg ein entsprechender Code, welcher ein, eine Ebene höheres, TRegion-Objekt verwendet, verfügbar in Lazarus 0.9.31+ (Hinweis: auch die vorherige Vorgehensweise wird in Zukunft weiterhin unterstützt werden):
176186
177187``` pascal
178188uses Graphics;
179189
180190procedure TForm1.FormCreate(Sender: TObject);
181191var
182192 MyRegion: TRegion;
183193begin
184194 MyRegion := TRegion.Create;
185195 try
186196 MyRegion.AddRectangle(0, 0, 100, 100);
187197 Self.SetShape(MyRegion);
188198 finally
189199 MyRegion.Free;
190200 end;
191201end;
192202```
193203
194204Ein Ergebnis dieses Vorgehens, bei einem Fenster auf einem Mac OS X, welches das Qt Widgetset genutzt hat, sehen Sie hier:
195205
196206![](/wiki-images/7/72/Non_rectangular_window.png)
197207
198208Beachten Sie, dass SetShape auch ein TBitmap nutzen kann, um eine transparente Region zu beschreiben.
199209
200210Siehe auch:
201211
202212- [[LCL Internals|LCL_Internals#Shaped_Windows]]
203213
204214Dokumentationen:
205215
206216- <http://lazarus-ccr.sourceforge.net/docs/lcl/lclintf/setwindowrgn.html>
207217- <http://lazarus-ccr.sourceforge.net/docs/lcl/controls/twincontrol.setshape.html>
208218
209219Einschränkungen:
210220
211221In Gtk2 kann eine Region erst festgelegt werden, nachdem ein Fenster erstellt wurde. SetWindowRgn im OnShow-Ereignishandler aufzurufen funktioniert nicht, die einzige Möglichkeit scheint der Einsatz eines Timers zu sein, der nach einem Intervall von 1 ms aufgerufen wird. Aktivieren Sie den Timer in Form.OnShow und deaktivieren Sie ihn im OnTimer-Handler.
212222
213223## Simulation von Maus- and Tastatureingaben
214224
215225Sie können sehr einfach Maus- und Tastatureingaben mit der LCL simulieren. Nutzen Sie dazu einfach die Routinen aus der Unit LCLMessageGlue wie es alle Widgetset Schnittstellen tun. Diese Unit verfügt über Routinen wie:
216226
217227``` pascal
218228unit LCLMessageGlue;
219229
220230function LCLSendMouseMoveMsg(const Target: TControl; XPos, YPos: smallint;
221231 ShiftState: TShiftState = []): PtrInt;
222232function LCLSendMouseDownMsg(const Target: TControl; XPos, YPos: smallint;
223233 Button: TMouseButton; ShiftState: TShiftState = []): PtrInt;
224234function LCLSendMouseUpMsg(const Target: TControl; XPos, YPos: smallint;
225235 Button: TMouseButton; ShiftState: TShiftState = []): PtrInt;
226236function LCLSendMouseWheelMsg(const Target: TControl; XPos, YPos, WheelDelta: smallint;
227237 ShiftState: TShiftState = []): PtrInt;
228238function LCLSendCaptureChangedMsg(const Target: TControl): PtrInt;
229239function LCLSendSelectionChangedMsg(const Target: TControl): PtrInt;
230240function LCLSendClickedMsg(const Target: TControl): PtrInt;
231241function LCLSendMouseEnterMsg(const Target: TControl): PtrInt;
232242function LCLSendMouseLeaveMsg(const Target: TControl): PtrInt;
233243...
234244function LCLSendKeyDownEvent(const Target: TControl; var CharCode: word;
235245 KeyData: PtrInt; BeforeEvent, IsSysKey: boolean): PtrInt;
236246function LCLSendKeyUpEvent(const Target: TControl; var CharCode: word;
237247 KeyData: PtrInt; BeforeEvent, IsSysKey: boolean): PtrInt;
238248```
239249
240250## Die virtuelle Tastatur auf Smartphones/Tablets zeigen
241251
242252Um die virtuelle Tastatur anzuzeigen, wenn ein Steuerelement den Fokus erhält, können Sie einfach csRequiresKeyboardInput ControlStyle hinzufügen:
243253
244254``` pascal
245255constructor TMyTextEditor.Create(AOwner : TComponent);
246256begin
247257 inherited Create(AOwner);
248258 ControlStyle := ControlStyle + [csRequiresKeyboardInput];
249259...
250260end;
251261```
252262
253263![](/wiki-images/2/29/Virtual_keyboard.png)
254264
255265## Alle untergeordneten Controls von einem TWinControl durchlaufen
256266
257267Dies ist sehr einfach zu realisieren. Benutzen Sie einfach eine Schleife. Der Index ist nullbasiert, TWinControl.ControlCount gibt die Anzahl an und TWinControl.Controls\[Index\] das entspechende Steuerelement.
258268
259269``` pascal
260270procedure TWinControl.WriteLayoutDebugReport(const Prefix: string);
261271var
262272 i: Integer;
263273begin
264274 inherited WriteLayoutDebugReport(Prefix);
265275 for i:=0 to ControlCount-1 do
266276 Controls[i].WriteLayoutDebugReport(Prefix+' ');
267277end;
268278```
269279
270280---
271281*From the Free Pascal wiki, page "LCL Tips/de", as it stood on 2020-02-19 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history