Sign in Join
Wiki copytemporary

LCL Tips/ru: what changed

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

OldNewLine
11## Создание графического интерфейса с помощью кода
22
33При работе в среде Lazarus, графический пользовательский интерфейс (GUI) можно полностью создавать с помощью Pascal-кода. При этом доступны все возможности, которые обычно используются через интерфейс IDE. Далее рассмотрены примеры программы и модуля (codegui.lpr and mainform.pas) которые вы можете использовать в качестве шаблона. Важнее всего – не забывать устанавливать свойство Parent компонентов. Элементы управления для размещения на форме лучше всего создавать в конструкторе формы:
44
55Файл основной программы:
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
2525Модуль, содержащий форму:
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
5555 Position := poScreenCenter;
5656 Height := 400;
5757 Width := 400;
5858
5959 VertScrollBar.Visible := False;
6060 HorzScrollBar.Visible := False;
6161
6262 MyButton := TButton.Create(Self);
6363 with MyButton do
6464 begin
6565 Height := 30;
6666 Left := 100;
6767 Top := 100;
6868 Width := 100;
6969 Caption := 'Закрыть';
7070 OnClick := ButtonClick;
7171 Parent := Self;
7272 end;
7373
7474 // Сюда можно добавить код создания других компонентов и установки их свойств
7575end;
7676
7777end.
7878```
7979
8080## Создание элементов управления вручную без потери быстродействия
8181
8282### Устанавливайте свойство Parent в последнюю очередь
8383
8484**Для пользователей, перешедших с Delphi**: В отличие от Delphi, LCL позволяет устанавливать практически все свойства в любой последовательности. Например, в Delphi невозможно установить позицию элемента управления, если для него не установлен родительский элемент (свойство Parent). LCL позволяет это сделать, и это можно использовать для повышения быстродействия.
8585
8686``` pascal
8787 with TButton.Create(Form1) do begin
8888 // 1. создаём кнопку с размером по умолчанию
8989 // 2. изменяем положение. Пока ничего не меняется, потому что Parent=nil
9090 SetBounds(10,10,Width,Height);
9191 // 3. изменяем размер в зависимости от темы.
9292 // Пока что размер не меняется, потому что Parent=nil
9393 AutoSize:=true;
9494 // 4. далее размер должен поменяться из-за включенного свойства AutoSize
9595 // Но опять это изменение откладывается, потому что Parent=nil
9696 Caption:='ОК';
9797 // 5. устанавливаем свойство Parent. Вот теперь все изменения применяются,
9898 // но за один раз, как одно действие.
9999 Parent:=Form1;
100100 end;
101101```
102102
103103Когда для элемента управления задано свойство Parent, все изменения его свойств сразу же применяются. Когда свойство Parent не задано, многие свойства только изменяют хранимое значение, и как только Parent будет установлен, все изменения будут применены. Это особенно актуально для компонентов-"внуков":
104104
105105``` pascal
106106 GroupBox1:=TGroupBox.Create(Self);
107107 with GroupBox1 do begin
108108 with TButton1.Create(Self) do begin
109109 AutoSize:=true;
110110 Caption:='Нажми меня';
111111 Parent:=GroupBox1;
112112 end;
113113 Parent:=Form1;
114114 end;
115115 Form1.Show;
116116```
117117
118118Автоматическая установка размера начинается только когда для всех элементов установлены родительские элементы и форма становится видимой.
119119
120120### Избегайте раннего создания хэндла (Handle)
121121
122122Как только для TWinControl создаётся хэндл, все изменения свойств элемента начинают менять его графическое представление (называемое виджетом). Даже если элемент невидим, если у него есть хэндл, изменения требуют много вычислительных ресурсов.
123123
124124### Используйте SetBounds вместо Left, Top, Width, Height
125125
126126Вместо
127127
128128``` pascal
129129 with Button1 do begin
130130 Left:=10;
131131 Top:=10;
132132 Width:=100;
133133 Height:=25;
134134 end;
135135```
136136
137137используйте
138138
139139``` pascal
140140 with Button1 do begin
141141 SetBounds(10,10,100,25);
142142 end;
143143```
144144
145145Left, Top, Width, Height вызывают SetBounds, и каждое изменение размера или позиции приводит к повторному вычислению параметров соседних элементов, и возможно рекурсивному вычислению параметров родительских и/или дочерних элементов.
146146
147147## DisableAlign/EnableAlign
148148
149149При позиционировании многих элементов управления полезно отключать автоматическое вычисление размера, выравнивания и привязок.
150150
151151``` pascal
152152 DisableAlign;
153153 try
154154 ListBox1.Width:=ClientWidth div 3;
155155 ListBox2.Width:=ClientWidth div 3;
156156 ListBox3.Width:=ClientWidth div 3;
157157 finally
158158 EnableAlign;
159159 end;
160160```
161161
162162> **Note:** Каждый вызов DisableAlign требует вызова EnableAlign. Например, если вы вызываете DisableAlign два раза, то должны вызвать EnableAlign тоже два раза.
163163
164164**Для пользователей, перешедших с Delphi**: Данные вызовы работают рекурсивно. DisableAlign запрещает выравнивание всех дочерних элементов, элементов-"внуков" и т.д.
165165
166166## Создание не прямоугольных окон или элементов управления
167167
168168В Lazarus можно легко создавать не прямоугольные окна или элементы управления. Для этого можно просто вызвать TWinControl.SetShape с видимой областью в качестве параметра. Обратите внимание, что это будет работать как для окон, так и для элементов управления, так как TCustomForm и TCustomControl происходят от TWinControl. Можно также вызвать подпрограмму LCLIntf SetWindowRgn, которая полностью эквивалентна вызову метода SetShape.
169169
170170С использованием SetWindowRgn код будет похож на следующий:
171171
172172``` pascal
173173uses LCLIntf, LCLType;
174174
175175procedure TForm1.FormCreate(Sender: TObject);
176176var
177177 MyRegion: HRGN;
178178begin
179179 MyRegion := CreateRectRgn(0, 0, 100, 100);
180180 SetWindowRgn(Handle, MyRegion, True);
181181 DeleteObject(MyRegion);
182182end;
183183```
184184
185185Эквивалентный код, который использует объект TRegion более высокого уровня, доступен в Lazarus 0.9.31+ (обратите внимание, что предыдущий способ работы все еще поддерживается и будет \[поддерживаться\] в будущем):
186186
187187``` pascal
188188uses Graphics;
189189
190190procedure TForm1.FormCreate(Sender: TObject);
191191var
192192 MyRegion: TRegion;
193193begin
194194 MyRegion := TRegion.Create;
195195 try
196196 MyRegion.AddRectangle(0, 0, 100, 100);
197197 Self.SetShape(MyRegion);
198198 finally
199199 MyRegion.Free;
200200 end;
201201end;
202202```
203203
204204Результат этой операции в окне в macOS с использованием набора виджетов Qt можно увидеть здесь:
205205
206-<figure>
207-<img src="non_rectangular_window.png" title="non_rectangular_window.png" />
208-<figcaption>non_rectangular_window.png</figcaption>
209-</figure>
206+![](/wiki-images/7/72/Non_rectangular_window.png)
210207
211208Обратите внимание, что SetShape также может принять TBitmap для описания прозрачной области.
212209
213210См.также:
214211
215212- [[LCL Internals|LCL_Internals#Shaped_Windows]]
216213
217214Соответствующая документация:
218215
219216- <http://lazarus-ccr.sourceforge.net/docs/lcl/lclintf/setwindowrgn.html>
220217- <http://lazarus-ccr.sourceforge.net/docs/lcl/controls/twincontrol.setshape.html>
221218
222219Ограничения:
223220
224221В Gtk2 регион может быть установлен только после того, как окно реализовано. Вызов SetWindowRgn в обработчике события OnShow не работает, единственный способ - вызвать его, например, из таймера, установленного с интервалом 1. Включите таймер в Form.OnShow и отключите его в обработчике OnTimer.
225222
226223## Имитация событий мыши и ввода с клавиатуры
227224
228225Имитировать ввод с помощью мыши и клавиатуры в LCL очень легко, просто используйте процедуры из модуля LCLMessageGlue, как это делают все интерфейсы widgetset. Этот модуль имеет процедуры, такие как:
229226
230227``` pascal
231228unit LCLMessageGlue;
232229
233230function LCLSendMouseMoveMsg(const Target: TControl; XPos, YPos: smallint;
234231 ShiftState: TShiftState = []): PtrInt;
235232function LCLSendMouseDownMsg(const Target: TControl; XPos, YPos: smallint;
236233 Button: TMouseButton; ShiftState: TShiftState = []): PtrInt;
237234function LCLSendMouseUpMsg(const Target: TControl; XPos, YPos: smallint;
238235 Button: TMouseButton; ShiftState: TShiftState = []): PtrInt;
239236function LCLSendMouseWheelMsg(const Target: TControl; XPos, YPos, WheelDelta: smallint;
240237 ShiftState: TShiftState = []): PtrInt;
241238function LCLSendCaptureChangedMsg(const Target: TControl): PtrInt;
242239function LCLSendSelectionChangedMsg(const Target: TControl): PtrInt;
243240function LCLSendClickedMsg(const Target: TControl): PtrInt;
244241function LCLSendMouseEnterMsg(const Target: TControl): PtrInt;
245242function LCLSendMouseLeaveMsg(const Target: TControl): PtrInt;
246243...
247244function LCLSendKeyDownEvent(const Target: TControl; var CharCode: word;
248245 KeyData: PtrInt; BeforeEvent, IsSysKey: boolean): PtrInt;
249246function LCLSendKeyUpEvent(const Target: TControl; var CharCode: word;
250247 KeyData: PtrInt; BeforeEvent, IsSysKey: boolean): PtrInt;
251248```
252249
253250## Показ виртуальной клавиатуры в смартфоне/планшете
254251
255252Чтобы показать виртуальную клавиатуру, когда виджет получает фокус, в ControlStyle просто добавьте csRequiresKeyboardInput:
256253
257254``` pascal
258255constructor TMyTextEditor.Create(AOwner : TComponent);
259256begin
260257 inherited Create(AOwner);
261258 ControlStyle := ControlStyle + [csRequiresKeyboardInput];
262259...
263260end;
264261```
265262
266-<figure>
267-<img src="Virtual_keyboard.png" title="Virtual_keyboard.png" />
268-<figcaption>Virtual_keyboard.png</figcaption>
269-</figure>
263+![](/wiki-images/2/29/Virtual_keyboard.png)
270264
271265## Перебор по всем дочерним элементам управления TWinControl
272266
273267Это очень легко, просто используйте цикл для перебора TWinControl.ControlCount и TWinControl.Controls\[Index\]. Индекс начинается с нуля.
274268
275269``` pascal
276270procedure TWinControl.WriteLayoutDebugReport(const Prefix: string);
277271var
278272 i: Integer;
279273begin
280274 inherited WriteLayoutDebugReport(Prefix);
281275 for i:=0 to ControlCount-1 do
282276 Controls[i].WriteLayoutDebugReport(Prefix+' ');
283277end;
284278```
285279
286280---
287281*From the Free Pascal wiki, page "LCL Tips/ru", as it stood on 2019-12-22 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).*
288282Category: LCL/ru
289283Category: Russian
290284Category: Russian (unfinished translation)

Back to history