Sign in Join
Wiki copytemporary

LCL Tips/ru: what changed

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

Title: LCL Tips/ru

OldNewLine
1+## Создание графического интерфейса с помощью кода
2+
3+При работе в среде Lazarus, графический пользовательский интерфейс (GUI) можно полностью создавать с помощью Pascal-кода. При этом доступны все возможности, которые обычно используются через интерфейс IDE. Далее рассмотрены примеры программы и модуля (codegui.lpr and mainform.pas) которые вы можете использовать в качестве шаблона. Важнее всего – не забывать устанавливать свойство Parent компонентов. Элементы управления для размещения на форме лучше всего создавать в конструкторе формы:
4+
5+Файл основной программы:
6+
7+``` pascal
8+program codedgui;
9+
10+{$MODE DELPHI}{$H+}
11+
12+uses
13+ Interfaces, Forms, StdCtrls,
14+ MainForm;
15+
16+var
17+ MyForm: TMyForm;
18+begin
19+ Application.Initialize;
20+ Application.CreateForm(TMyForm, MyForm);
21+ Application.Run;
22+end.
23+```
24+
25+Модуль, содержащий форму:
26+
27+``` pascal
28+unit mainform;
29+
30+{$MODE DELPHI}{$H+}
31+
32+interface
33+
34+uses Forms, StdCtrls;
35+
36+type
37+ TMyForm = class(TForm)
38+ public
39+ MyButton: TButton;
40+ procedure ButtonClick(ASender: TObject);
41+ constructor Create(AOwner: TComponent); override;
42+ end;
43+
44+implementation
45+
46+procedure TMyForm.ButtonClick(ASender:TObject);
47+begin
48+ Close;
49+end;
50+
51+constructor TMyForm.Create(AOwner: TComponent);
52+begin
53+ inherited Create(AOwner);
54+
55+ Position := poScreenCenter;
56+ Height := 400;
57+ Width := 400;
58+
59+ VertScrollBar.Visible := False;
60+ HorzScrollBar.Visible := False;
61+
62+ MyButton := TButton.Create(Self);
63+ with MyButton do
64+ begin
65+ Height := 30;
66+ Left := 100;
67+ Top := 100;
68+ Width := 100;
69+ Caption := 'Закрыть';
70+ OnClick := ButtonClick;
71+ Parent := Self;
72+ end;
73+
74+ // Сюда можно добавить код создания других компонентов и установки их свойств
75+end;
76+
77+end.
78+```
79+
80+## Создание элементов управления вручную без потери быстродействия
81+
82+### Устанавливайте свойство Parent в последнюю очередь
83+
84+**Для пользователей, перешедших с Delphi**: В отличие от Delphi, LCL позволяет устанавливать практически все свойства в любой последовательности. Например, в Delphi невозможно установить позицию элемента управления, если для него не установлен родительский элемент (свойство Parent). LCL позволяет это сделать, и это можно использовать для повышения быстродействия.
85+
86+``` pascal
87+ with TButton.Create(Form1) do begin
88+ // 1. создаём кнопку с размером по умолчанию
89+ // 2. изменяем положение. Пока ничего не меняется, потому что Parent=nil
90+ SetBounds(10,10,Width,Height);
91+ // 3. изменяем размер в зависимости от темы.
92+ // Пока что размер не меняется, потому что Parent=nil
93+ AutoSize:=true;
94+ // 4. далее размер должен поменяться из-за включенного свойства AutoSize
95+ // Но опять это изменение откладывается, потому что Parent=nil
96+ Caption:='ОК';
97+ // 5. устанавливаем свойство Parent. Вот теперь все изменения применяются,
98+ // но за один раз, как одно действие.
99+ Parent:=Form1;
100+ end;
101+```
102+
103+Когда для элемента управления задано свойство Parent, все изменения его свойств сразу же применяются. Когда свойство Parent не задано, многие свойства только изменяют хранимое значение, и как только Parent будет установлен, все изменения будут применены. Это особенно актуально для компонентов-"внуков":
104+
105+``` pascal
106+ GroupBox1:=TGroupBox.Create(Self);
107+ with GroupBox1 do begin
108+ with TButton1.Create(Self) do begin
109+ AutoSize:=true;
110+ Caption:='Нажми меня';
111+ Parent:=GroupBox1;
112+ end;
113+ Parent:=Form1;
114+ end;
115+ Form1.Show;
116+```
117+
118+Автоматическая установка размера начинается только когда для всех элементов установлены родительские элементы и форма становится видимой.
119+
120+### Избегайте раннего создания хэндла (Handle)
121+
122+Как только для TWinControl создаётся хэндл, все изменения свойств элемента начинают менять его графическое представление (называемое виджетом). Даже если элемент невидим, если у него есть хэндл, изменения требуют много вычислительных ресурсов.
123+
124+### Используйте SetBounds вместо Left, Top, Width, Height
125+
126+Вместо
127+
128+``` pascal
129+ with Button1 do begin
130+ Left:=10;
131+ Top:=10;
132+ Width:=100;
133+ Height:=25;
134+ end;
135+```
136+
137+используйте
138+
139+``` pascal
140+ with Button1 do begin
141+ SetBounds(10,10,100,25);
142+ end;
143+```
144+
145+Left, Top, Width, Height вызывают SetBounds, и каждое изменение размера или позиции приводит к повторному вычислению параметров соседних элементов, и возможно рекурсивному вычислению параметров родительских и/или дочерних элементов.
146+
147+## DisableAlign/EnableAlign
148+
149+При позиционировании многих элементов управления полезно отключать автоматическое вычисление размера, выравнивания и привязок.
150+
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+```
161+
162+> **Note:** Каждый вызов DisableAlign требует вызова EnableAlign. Например, если вы вызываете DisableAlign два раза, то должны вызвать EnableAlign тоже два раза.
163+
164+**Для пользователей, перешедших с Delphi**: Данные вызовы работают рекурсивно. DisableAlign запрещает выравнивание всех дочерних элементов, элементов-"внуков" и т.д.
165+
166+## Создание не прямоугольных окон или элементов управления
167+
168+В Lazarus можно легко создавать не прямоугольные окна или элементы управления. Для этого можно просто вызвать TWinControl.SetShape с видимой областью в качестве параметра. Обратите внимание, что это будет работать как для окон, так и для элементов управления, так как TCustomForm и TCustomControl происходят от TWinControl. Можно также вызвать подпрограмму LCLIntf SetWindowRgn, которая полностью эквивалентна вызову метода SetShape.
169+
170+С использованием SetWindowRgn код будет похож на следующий:
171+
172+``` pascal
173+uses LCLIntf, LCLType;
174+
175+procedure TForm1.FormCreate(Sender: TObject);
176+var
177+ MyRegion: HRGN;
178+begin
179+ MyRegion := CreateRectRgn(0, 0, 100, 100);
180+ SetWindowRgn(Handle, MyRegion, True);
181+ DeleteObject(MyRegion);
182+end;
183+```
184+
185+Эквивалентный код, который использует объект TRegion более высокого уровня, доступен в Lazarus 0.9.31+ (обратите внимание, что предыдущий способ работы все еще поддерживается и будет \[поддерживаться\] в будущем):
186+
187+``` pascal
188+uses Graphics;
189+
190+procedure TForm1.FormCreate(Sender: TObject);
191+var
192+ MyRegion: TRegion;
193+begin
194+ MyRegion := TRegion.Create;
195+ try
196+ MyRegion.AddRectangle(0, 0, 100, 100);
197+ Self.SetShape(MyRegion);
198+ finally
199+ MyRegion.Free;
200+ end;
201+end;
202+```
203+
204+Результат этой операции в окне в macOS с использованием набора виджетов Qt можно увидеть здесь:
205+
206+<figure>
207+<img src="non_rectangular_window.png" title="non_rectangular_window.png" />
208+<figcaption>non_rectangular_window.png</figcaption>
209+</figure>
210+
211+Обратите внимание, что SetShape также может принять TBitmap для описания прозрачной области.
212+
213+См.также:
214+
215+- [[LCL Internals|LCL_Internals#Shaped_Windows]]
216+
217+Соответствующая документация:
218+
219+- <http://lazarus-ccr.sourceforge.net/docs/lcl/lclintf/setwindowrgn.html>
220+- <http://lazarus-ccr.sourceforge.net/docs/lcl/controls/twincontrol.setshape.html>
221+
222+Ограничения:
223+
224+В Gtk2 регион может быть установлен только после того, как окно реализовано. Вызов SetWindowRgn в обработчике события OnShow не работает, единственный способ - вызвать его, например, из таймера, установленного с интервалом 1. Включите таймер в Form.OnShow и отключите его в обработчике OnTimer.
225+
226+## Имитация событий мыши и ввода с клавиатуры
227+
228+Имитировать ввод с помощью мыши и клавиатуры в LCL очень легко, просто используйте процедуры из модуля LCLMessageGlue, как это делают все интерфейсы widgetset. Этот модуль имеет процедуры, такие как:
229+
230+``` pascal
231+unit LCLMessageGlue;
232+
233+function LCLSendMouseMoveMsg(const Target: TControl; XPos, YPos: smallint;
234+ ShiftState: TShiftState = []): PtrInt;
235+function LCLSendMouseDownMsg(const Target: TControl; XPos, YPos: smallint;
236+ Button: TMouseButton; ShiftState: TShiftState = []): PtrInt;
237+function LCLSendMouseUpMsg(const Target: TControl; XPos, YPos: smallint;
238+ Button: TMouseButton; ShiftState: TShiftState = []): PtrInt;
239+function LCLSendMouseWheelMsg(const Target: TControl; XPos, YPos, WheelDelta: smallint;
240+ ShiftState: TShiftState = []): PtrInt;
241+function LCLSendCaptureChangedMsg(const Target: TControl): PtrInt;
242+function LCLSendSelectionChangedMsg(const Target: TControl): PtrInt;
243+function LCLSendClickedMsg(const Target: TControl): PtrInt;
244+function LCLSendMouseEnterMsg(const Target: TControl): PtrInt;
245+function LCLSendMouseLeaveMsg(const Target: TControl): PtrInt;
246+...
247+function LCLSendKeyDownEvent(const Target: TControl; var CharCode: word;
248+ KeyData: PtrInt; BeforeEvent, IsSysKey: boolean): PtrInt;
249+function LCLSendKeyUpEvent(const Target: TControl; var CharCode: word;
250+ KeyData: PtrInt; BeforeEvent, IsSysKey: boolean): PtrInt;
251+```
252+
253+## Показ виртуальной клавиатуры в смартфоне/планшете
254+
255+Чтобы показать виртуальную клавиатуру, когда виджет получает фокус, в ControlStyle просто добавьте csRequiresKeyboardInput:
256+
257+``` pascal
258+constructor TMyTextEditor.Create(AOwner : TComponent);
259+begin
260+ inherited Create(AOwner);
261+ ControlStyle := ControlStyle + [csRequiresKeyboardInput];
262+...
263+end;
264+```
265+
266+<figure>
267+<img src="Virtual_keyboard.png" title="Virtual_keyboard.png" />
268+<figcaption>Virtual_keyboard.png</figcaption>
269+</figure>
270+
271+## Перебор по всем дочерним элементам управления TWinControl
272+
273+Это очень легко, просто используйте цикл для перебора TWinControl.ControlCount и TWinControl.Controls\[Index\]. Индекс начинается с нуля.
274+
275+``` pascal
276+procedure TWinControl.WriteLayoutDebugReport(const Prefix: string);
277+var
278+ i: Integer;
279+begin
280+ inherited WriteLayoutDebugReport(Prefix);
281+ for i:=0 to ControlCount-1 do
282+ Controls[i].WriteLayoutDebugReport(Prefix+' ');
283+end;
284+```
285+
286+---
287+*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).*
288+Category: LCL/ru
289+Category: Russian
290+Category: Russian (unfinished translation)

Back to history