Sign in Join
Wiki copytemporary

LCL Tips/de: what changed

Revision 1 to 2. 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
8989` with TButton.Create(Form1) do begin`\
9090`   // 1. Erzeugen eines button setzt die Vorgabegröße`\
9191`   // 2. Ändern der Position. Keine Randeffekte, weil Parent=nil`\
9292`   SetBounds(10,10,Width,Height);`\
9393`   // 3. Ändern der Größe abhängig vom Thema. Noch nicht, weil Parent=nil`\
9494`   AutoSize:=true;`\
9595`   // 4. Ändern der Größe wegen AutoSize=true. Noch nicht, weil Parent=nil`\
9696`   Caption:='Ok';`\
9797`   // 5. Setzen sie Parent. Jetzt geschieht all das obige, aber in einer einzigen Aktion.`\
9898`   Parent:=Form1;`\
9999` end;`
100100
101101Wenn 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:
102102
103103` GroupBox1:=TGroupBox.Create(Self);`\
104104` with GroupBox1 do begin`\
105105`   with TButton1.Create(Self) do begin`\
106106`     AutoSize:=true;`\
107107`     Caption:='Click me';`\
108108`     Parent:=GroupBox1;`\
109109`   end;`\
110110`   Parent:=Form1;`\
111111` end;`\
112112` Form1.Show;`
113113
114114Autosizing startet nicht bevor jeder parent eingerichtet ist und das Formular sichtbar wird.
115115
116116### Vermeiden sie eine frühe Handle Erzeugung
117117
118118Sobald 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.
119119
120120### Verwenden sie SetBounds anstelle von Left, Top, Width, Height
121121
122122Anstelle von
123123
124124` with Button1 do begin`\
125125`   Left:=10;`\
126126`   Top:=10;`\
127127`   Width:=100;`\
128128`   Height:=25;`\
129129` end;`
130130
131131verwenden sie
132132
133133` with Button1 do begin`\
134134`   SetBounds(10,10,100,25);`\
135135` end;`
136136
137137Left, 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.
138138
139139## DisableAlign / EnableAlign
140140
141141Wenn sie viele Bedienelemente positionieren, ist es eine gute Idee, die Neuberechnungvon all auto sizing, aligning, anchoring zu deaktivieren.
142142
143143` DisableAlign;`\
144144` try`\
145145`   ListBox1.Width:=ClientWidth div 3;`\
146146`   ListBox2.Width:=ClientWidth div 3;`\
147147`   ListBox3.Width:=ClientWidth div 3;`\
148148` finally`\
149149`   EnableAlign;`\
150150` end;`
151151
152152**Anmerkung**: Jeder DisableAlign Aufruf benötigt einen EnableAlign Aufruf. Zum Beispiel wenn sie DisableAlign zweimal aufrufen, müssen sie auch EnableAlign zweimal aufrufen.
153153
154154**Für Delphianer**: Dies funktioniert rekursiv. Das bedeutet, DisableAlign stoppt aligning in allen childs und grand childs.
155155
156156## Ein nicht-rechteckiges Fenster oder Steuerelement erstellen
157157
158158Sie 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.
159159
160160Mit SetWindowRgn wird der Code wie folgt aussehen:
161161
162162``` pascal
163163uses LCLIntf, LCLType;
164164
165165procedure TForm1.FormCreate(Sender: TObject);
166166var
167167 MyRegion: HRGN;
168168begin
169169 MyRegion := CreateRectRgn(0, 0, 100, 100);
170170 SetWindowRgn(Handle, MyRegion, True);
171171 DeleteObject(MyRegion);
172172end;
173173```
174174
175175Nachfolg 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):
176176
177177``` pascal
178178uses Graphics;
179179
180180procedure TForm1.FormCreate(Sender: TObject);
181181var
182182 MyRegion: TRegion;
183183begin
184184 MyRegion := TRegion.Create;
185185 try
186186 MyRegion.AddRectangle(0, 0, 100, 100);
187187 Self.SetShape(MyRegion);
188188 finally
189189 MyRegion.Free;
190190 end;
191191end;
192192```
193193
194194Ein Ergebnis dieses Vorgehens, bei einem Fenster auf einem Mac OS X, welches das Qt Widgetset genutzt hat, sehen Sie hier:
195195
196-<figure>
197-<img src="non_rectangular_window.png" title="non_rectangular_window.png" />
198-<figcaption>non_rectangular_window.png</figcaption>
199-</figure>
196+![](/wiki-images/7/72/Non_rectangular_window.png)
200197
201198Beachten Sie, dass SetShape auch ein TBitmap nutzen kann, um eine transparente Region zu beschreiben.
202199
203200Siehe auch:
204201
205202- [[LCL Internals|LCL_Internals#Shaped_Windows]]
206203
207204Dokumentationen:
208205
209206- <http://lazarus-ccr.sourceforge.net/docs/lcl/lclintf/setwindowrgn.html>
210207- <http://lazarus-ccr.sourceforge.net/docs/lcl/controls/twincontrol.setshape.html>
211208
212209Einschränkungen:
213210
214211In 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.
215212
216213## Simulation von Maus- and Tastatureingaben
217214
218215Sie 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:
219216
220217``` pascal
221218unit LCLMessageGlue;
222219
223220function LCLSendMouseMoveMsg(const Target: TControl; XPos, YPos: smallint;
224221 ShiftState: TShiftState = []): PtrInt;
225222function LCLSendMouseDownMsg(const Target: TControl; XPos, YPos: smallint;
226223 Button: TMouseButton; ShiftState: TShiftState = []): PtrInt;
227224function LCLSendMouseUpMsg(const Target: TControl; XPos, YPos: smallint;
228225 Button: TMouseButton; ShiftState: TShiftState = []): PtrInt;
229226function LCLSendMouseWheelMsg(const Target: TControl; XPos, YPos, WheelDelta: smallint;
230227 ShiftState: TShiftState = []): PtrInt;
231228function LCLSendCaptureChangedMsg(const Target: TControl): PtrInt;
232229function LCLSendSelectionChangedMsg(const Target: TControl): PtrInt;
233230function LCLSendClickedMsg(const Target: TControl): PtrInt;
234231function LCLSendMouseEnterMsg(const Target: TControl): PtrInt;
235232function LCLSendMouseLeaveMsg(const Target: TControl): PtrInt;
236233...
237234function LCLSendKeyDownEvent(const Target: TControl; var CharCode: word;
238235 KeyData: PtrInt; BeforeEvent, IsSysKey: boolean): PtrInt;
239236function LCLSendKeyUpEvent(const Target: TControl; var CharCode: word;
240237 KeyData: PtrInt; BeforeEvent, IsSysKey: boolean): PtrInt;
241238```
242239
243240## Die virtuelle Tastatur auf Smartphones/Tablets zeigen
244241
245242Um die virtuelle Tastatur anzuzeigen, wenn ein Steuerelement den Fokus erhält, können Sie einfach csRequiresKeyboardInput ControlStyle hinzufügen:
246243
247244``` pascal
248245constructor TMyTextEditor.Create(AOwner : TComponent);
249246begin
250247 inherited Create(AOwner);
251248 ControlStyle := ControlStyle + [csRequiresKeyboardInput];
252249...
253250end;
254251```
255252
256-<figure>
257-<img src="Virtual_keyboard.png" title="Virtual_keyboard.png" />
258-<figcaption>Virtual_keyboard.png</figcaption>
259-</figure>
253+![](/wiki-images/2/29/Virtual_keyboard.png)
260254
261255## Alle untergeordneten Controls von einem TWinControl durchlaufen
262256
263257Dies 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.
264258
265259``` pascal
266260procedure TWinControl.WriteLayoutDebugReport(const Prefix: string);
267261var
268262 i: Integer;
269263begin
270264 inherited WriteLayoutDebugReport(Prefix);
271265 for i:=0 to ControlCount-1 do
272266 Controls[i].WriteLayoutDebugReport(Prefix+' ');
273267end;
274268```
275269
276270---
277271*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