Difference between revisions of "LCL Tips/ru"
m (→Создание не прямоугольных окон или элементов управления: OSX -> macOS) |
|||
(14 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
{{LCL Tips}} | {{LCL Tips}} | ||
− | = Создание графического интерфейса с помощью кода = | + | __TOC__ |
+ | == Создание графического интерфейса с помощью кода == | ||
При работе в среде Lazarus, графический пользовательский интерфейс (GUI) можно полностью создавать с помощью Pascal-кода. При этом доступны все возможности, которые обычно используются через интерфейс IDE. Далее рассмотрены примеры программы и модуля (codegui.lpr and mainform.pas) которые вы можете использовать в качестве шаблона. Важнее всего – не забывать устанавливать свойство Parent компонентов. Элементы управления для размещения на форме лучше всего создавать в конструкторе формы: | При работе в среде Lazarus, графический пользовательский интерфейс (GUI) можно полностью создавать с помощью Pascal-кода. При этом доступны все возможности, которые обычно используются через интерфейс IDE. Далее рассмотрены примеры программы и модуля (codegui.lpr and mainform.pas) которые вы можете использовать в качестве шаблона. Важнее всего – не забывать устанавливать свойство Parent компонентов. Элементы управления для размещения на форме лучше всего создавать в конструкторе формы: | ||
Line 7: | Line 8: | ||
Файл основной программы: | Файл основной программы: | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
program codedgui; | program codedgui; | ||
Line 27: | Line 28: | ||
Модуль, содержащий форму: | Модуль, содержащий форму: | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
unit mainform; | unit mainform; | ||
Line 80: | Line 81: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | = Создание элементов управления вручную без потери быстродействия = | + | == Создание элементов управления вручную без потери быстродействия == |
− | == Устанавливайте свойство Parent в последнюю очередь == | + | === Устанавливайте свойство Parent в последнюю очередь === |
'''Для пользователей, перешедших с Delphi''': В отличие от Delphi, LCL позволяет устанавливать практически все свойства в любой последовательности. Например, в Delphi невозможно установить позицию элемента управления, если для него не установлен родительский элемент (свойство Parent). LCL позволяет это сделать, и это можно использовать для повышения быстродействия. | '''Для пользователей, перешедших с Delphi''': В отличие от Delphi, LCL позволяет устанавливать практически все свойства в любой последовательности. Например, в Delphi невозможно установить позицию элемента управления, если для него не установлен родительский элемент (свойство Parent). LCL позволяет это сделать, и это можно использовать для повышения быстродействия. | ||
− | + | <syntaxhighlight lang="pascal"> | |
with TButton.Create(Form1) do begin | with TButton.Create(Form1) do begin | ||
// 1. создаём кнопку с размером по умолчанию | // 1. создаём кнопку с размером по умолчанию | ||
Line 100: | Line 101: | ||
Parent:=Form1; | Parent:=Form1; | ||
end; | end; | ||
− | + | </syntaxhighlight> | |
Когда для элемента управления задано свойство Parent, все изменения его свойств сразу же применяются. Когда свойство Parent не задано, многие свойства только изменяют хранимое значение, и как только Parent будет установлен, все изменения будут применены. Это особенно актуально для компонентов-"внуков": | Когда для элемента управления задано свойство Parent, все изменения его свойств сразу же применяются. Когда свойство Parent не задано, многие свойства только изменяют хранимое значение, и как только Parent будет установлен, все изменения будут применены. Это особенно актуально для компонентов-"внуков": | ||
− | + | <syntaxhighlight lang="pascal"> | |
GroupBox1:=TGroupBox.Create(Self); | GroupBox1:=TGroupBox.Create(Self); | ||
with GroupBox1 do begin | with GroupBox1 do begin | ||
Line 113: | Line 114: | ||
end; | end; | ||
Form1.Show; | Form1.Show; | ||
− | + | </syntaxhighlight> | |
Автоматическая установка размера начинается только когда для всех элементов установлены родительские элементы и форма становится видимой. | Автоматическая установка размера начинается только когда для всех элементов установлены родительские элементы и форма становится видимой. | ||
− | == Избегайте раннего создания хэндла (Handle) == | + | === Избегайте раннего создания хэндла (Handle) === |
Как только для TWinControl создаётся хэндл, все изменения свойств элемента начинают менять его графическое представление (называемое виджетом). Даже если элемент невидим, если у него есть хэндл, изменения требуют много вычислительных ресурсов. | Как только для TWinControl создаётся хэндл, все изменения свойств элемента начинают менять его графическое представление (называемое виджетом). Даже если элемент невидим, если у него есть хэндл, изменения требуют много вычислительных ресурсов. | ||
− | == Используйте SetBounds вместо Left, Top, Width, Height == | + | === Используйте SetBounds вместо Left, Top, Width, Height === |
Вместо | Вместо | ||
+ | <syntaxhighlight lang="pascal"> | ||
with Button1 do begin | with Button1 do begin | ||
Left:=10; | Left:=10; | ||
Line 129: | Line 131: | ||
Height:=25; | Height:=25; | ||
end; | end; | ||
+ | </syntaxhighlight> | ||
используйте | используйте | ||
+ | <syntaxhighlight lang="pascal"> | ||
with Button1 do begin | with Button1 do begin | ||
SetBounds(10,10,100,25); | SetBounds(10,10,100,25); | ||
end; | end; | ||
− | + | </syntaxhighlight> | |
Left, Top, Width, Height вызывают SetBounds, и каждое изменение размера или позиции приводит к повторному вычислению параметров соседних элементов, и возможно рекурсивному вычислению параметров родительских и/или дочерних элементов. | Left, Top, Width, Height вызывают SetBounds, и каждое изменение размера или позиции приводит к повторному вычислению параметров соседних элементов, и возможно рекурсивному вычислению параметров родительских и/или дочерних элементов. | ||
− | = DisableAlign / EnableAlign = | + | == DisableAlign/EnableAlign == |
При позиционировании многих элементов управления полезно отключать автоматическое вычисление размера, выравнивания и привязок. | При позиционировании многих элементов управления полезно отключать автоматическое вычисление размера, выравнивания и привязок. | ||
− | + | <syntaxhighlight lang="pascal"> | |
DisableAlign; | DisableAlign; | ||
try | try | ||
Line 148: | Line 152: | ||
EnableAlign; | EnableAlign; | ||
end; | end; | ||
− | + | </syntaxhighlight> | |
− | + | {{Note| Каждый вызов DisableAlign требует вызова EnableAlign. Например, если вы вызываете DisableAlign два раза, то должны вызвать EnableAlign тоже два раза.}} | |
'''Для пользователей, перешедших с Delphi''': Данные вызовы работают рекурсивно. DisableAlign запрещает выравнивание всех дочерних элементов, элементов-"внуков" и т.д. | '''Для пользователей, перешедших с Delphi''': Данные вызовы работают рекурсивно. DisableAlign запрещает выравнивание всех дочерних элементов, элементов-"внуков" и т.д. | ||
− | == | + | == Создание не прямоугольных окон или элементов управления == |
− | + | В Lazarus можно легко создавать не прямоугольные окна или элементы управления. Для этого можно просто вызвать TWinControl.SetShape с видимой областью в качестве параметра. Обратите внимание, что это будет работать как для окон, так и для элементов управления, так как TCustomForm и TCustomControl происходят от TWinControl. Можно также вызвать подпрограмму LCLIntf SetWindowRgn, которая полностью эквивалентна вызову метода SetShape. | |
− | + | С использованием SetWindowRgn код будет похож на следующий: | |
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
uses LCLIntf, LCLType; | uses LCLIntf, LCLType; | ||
Line 172: | Line 176: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | Эквивалентный код, который использует объект TRegion более высокого уровня, доступен в Lazarus 0.9.31+ (обратите внимание, что предыдущий способ работы все еще поддерживается и будет [поддерживаться] в будущем): | |
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
uses Graphics; | uses Graphics; | ||
Line 191: | Line 195: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | Результат этой операции в окне в macOS с использованием набора виджетов Qt можно увидеть здесь: | |
− | [[Image:non_rectangular_window.png]] | + | [[Image:non_rectangular_window.png|bottom]] |
− | + | Обратите внимание, что SetShape также может принять TBitmap для описания прозрачной области. | |
− | + | См.также: | |
* [[LCL_Internals#Shaped_Windows]] | * [[LCL_Internals#Shaped_Windows]] | ||
− | + | Соответствующая документация: | |
* http://lazarus-ccr.sourceforge.net/docs/lcl/lclintf/setwindowrgn.html | * http://lazarus-ccr.sourceforge.net/docs/lcl/lclintf/setwindowrgn.html | ||
* http://lazarus-ccr.sourceforge.net/docs/lcl/controls/twincontrol.setshape.html | * http://lazarus-ccr.sourceforge.net/docs/lcl/controls/twincontrol.setshape.html | ||
− | + | Ограничения: | |
− | + | В Gtk2 регион может быть установлен только после того, как окно реализовано. Вызов SetWindowRgn в обработчике события OnShow не работает, единственный способ - вызвать его, например, из таймера, установленного с интервалом 1. Включите таймер в Form.OnShow и отключите его в обработчике OnTimer. | |
− | == | + | ==Имитация событий мыши и ввода с клавиатуры== |
− | + | Имитировать ввод с помощью мыши и клавиатуры в LCL очень легко, просто используйте процедуры из модуля LCLMessageGlue, как это делают все интерфейсы widgetset. Этот модуль имеет процедуры, такие как: | |
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
unit LCLMessageGlue; | unit LCLMessageGlue; | ||
Line 237: | Line 241: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | == | + | ==Показ виртуальной клавиатуры в смартфоне/планшете== |
− | + | Чтобы показать виртуальную клавиатуру, когда виджет получает фокус, в ControlStyle просто добавьте csRequiresKeyboardInput: | |
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
constructor TMyTextEditor.Create(AOwner : TComponent); | constructor TMyTextEditor.Create(AOwner : TComponent); | ||
begin | begin | ||
Line 250: | Line 254: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | [[Image:Virtual_keyboard.png]] | + | [[Image:Virtual_keyboard.png|bottom]] |
− | == | + | ==Перебор по всем дочерним элементам управления TWinControl== |
− | + | Это очень легко, просто используйте цикл для перебора TWinControl.ControlCount и TWinControl.Controls[Index]. Индекс начинается с нуля. | |
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
procedure TWinControl.WriteLayoutDebugReport(const Prefix: string); | procedure TWinControl.WriteLayoutDebugReport(const Prefix: string); | ||
var | var |
Latest revision as of 06:45, 22 December 2019
│
Deutsch (de) │
English (en) │
français (fr) │
русский (ru) │
中文(中国大陆) (zh_CN) │
Создание графического интерфейса с помощью кода
При работе в среде Lazarus, графический пользовательский интерфейс (GUI) можно полностью создавать с помощью Pascal-кода. При этом доступны все возможности, которые обычно используются через интерфейс IDE. Далее рассмотрены примеры программы и модуля (codegui.lpr and mainform.pas) которые вы можете использовать в качестве шаблона. Важнее всего – не забывать устанавливать свойство Parent компонентов. Элементы управления для размещения на форме лучше всего создавать в конструкторе формы:
Файл основной программы:
program codedgui;
{$MODE DELPHI}{$H+}
uses
Interfaces, Forms, StdCtrls,
MainForm;
var
MyForm: TMyForm;
begin
Application.Initialize;
Application.CreateForm(TMyForm, MyForm);
Application.Run;
end.
Модуль, содержащий форму:
unit mainform;
{$MODE DELPHI}{$H+}
interface
uses Forms, StdCtrls;
type
TMyForm = class(TForm)
public
MyButton: TButton;
procedure ButtonClick(ASender: TObject);
constructor Create(AOwner: TComponent); override;
end;
implementation
procedure TMyForm.ButtonClick(ASender:TObject);
begin
Close;
end;
constructor TMyForm.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Position := poScreenCenter;
Height := 400;
Width := 400;
VertScrollBar.Visible := False;
HorzScrollBar.Visible := False;
MyButton := TButton.Create(Self);
with MyButton do
begin
Height := 30;
Left := 100;
Top := 100;
Width := 100;
Caption := 'Закрыть';
OnClick := ButtonClick;
Parent := Self;
end;
// Сюда можно добавить код создания других компонентов и установки их свойств
end;
end.
Создание элементов управления вручную без потери быстродействия
Устанавливайте свойство Parent в последнюю очередь
Для пользователей, перешедших с Delphi: В отличие от Delphi, LCL позволяет устанавливать практически все свойства в любой последовательности. Например, в Delphi невозможно установить позицию элемента управления, если для него не установлен родительский элемент (свойство Parent). LCL позволяет это сделать, и это можно использовать для повышения быстродействия.
with TButton.Create(Form1) do begin
// 1. создаём кнопку с размером по умолчанию
// 2. изменяем положение. Пока ничего не меняется, потому что Parent=nil
SetBounds(10,10,Width,Height);
// 3. изменяем размер в зависимости от темы.
// Пока что размер не меняется, потому что Parent=nil
AutoSize:=true;
// 4. далее размер должен поменяться из-за включенного свойства AutoSize
// Но опять это изменение откладывается, потому что Parent=nil
Caption:='ОК';
// 5. устанавливаем свойство Parent. Вот теперь все изменения применяются,
// но за один раз, как одно действие.
Parent:=Form1;
end;
Когда для элемента управления задано свойство Parent, все изменения его свойств сразу же применяются. Когда свойство Parent не задано, многие свойства только изменяют хранимое значение, и как только Parent будет установлен, все изменения будут применены. Это особенно актуально для компонентов-"внуков":
GroupBox1:=TGroupBox.Create(Self);
with GroupBox1 do begin
with TButton1.Create(Self) do begin
AutoSize:=true;
Caption:='Нажми меня';
Parent:=GroupBox1;
end;
Parent:=Form1;
end;
Form1.Show;
Автоматическая установка размера начинается только когда для всех элементов установлены родительские элементы и форма становится видимой.
Избегайте раннего создания хэндла (Handle)
Как только для TWinControl создаётся хэндл, все изменения свойств элемента начинают менять его графическое представление (называемое виджетом). Даже если элемент невидим, если у него есть хэндл, изменения требуют много вычислительных ресурсов.
Используйте SetBounds вместо Left, Top, Width, Height
Вместо
with Button1 do begin
Left:=10;
Top:=10;
Width:=100;
Height:=25;
end;
используйте
with Button1 do begin
SetBounds(10,10,100,25);
end;
Left, Top, Width, Height вызывают SetBounds, и каждое изменение размера или позиции приводит к повторному вычислению параметров соседних элементов, и возможно рекурсивному вычислению параметров родительских и/или дочерних элементов.
DisableAlign/EnableAlign
При позиционировании многих элементов управления полезно отключать автоматическое вычисление размера, выравнивания и привязок.
DisableAlign;
try
ListBox1.Width:=ClientWidth div 3;
ListBox2.Width:=ClientWidth div 3;
ListBox3.Width:=ClientWidth div 3;
finally
EnableAlign;
end;
Для пользователей, перешедших с Delphi: Данные вызовы работают рекурсивно. DisableAlign запрещает выравнивание всех дочерних элементов, элементов-"внуков" и т.д.
Создание не прямоугольных окон или элементов управления
В Lazarus можно легко создавать не прямоугольные окна или элементы управления. Для этого можно просто вызвать TWinControl.SetShape с видимой областью в качестве параметра. Обратите внимание, что это будет работать как для окон, так и для элементов управления, так как TCustomForm и TCustomControl происходят от TWinControl. Можно также вызвать подпрограмму LCLIntf SetWindowRgn, которая полностью эквивалентна вызову метода SetShape.
С использованием SetWindowRgn код будет похож на следующий:
uses LCLIntf, LCLType;
procedure TForm1.FormCreate(Sender: TObject);
var
MyRegion: HRGN;
begin
MyRegion := CreateRectRgn(0, 0, 100, 100);
SetWindowRgn(Handle, MyRegion, True);
DeleteObject(MyRegion);
end;
Эквивалентный код, который использует объект TRegion более высокого уровня, доступен в Lazarus 0.9.31+ (обратите внимание, что предыдущий способ работы все еще поддерживается и будет [поддерживаться] в будущем):
uses Graphics;
procedure TForm1.FormCreate(Sender: TObject);
var
MyRegion: TRegion;
begin
MyRegion := TRegion.Create;
try
MyRegion.AddRectangle(0, 0, 100, 100);
Self.SetShape(MyRegion);
finally
MyRegion.Free;
end;
end;
Результат этой операции в окне в macOS с использованием набора виджетов Qt можно увидеть здесь:
Обратите внимание, что SetShape также может принять TBitmap для описания прозрачной области.
См.также:
Соответствующая документация:
- http://lazarus-ccr.sourceforge.net/docs/lcl/lclintf/setwindowrgn.html
- http://lazarus-ccr.sourceforge.net/docs/lcl/controls/twincontrol.setshape.html
Ограничения:
В Gtk2 регион может быть установлен только после того, как окно реализовано. Вызов SetWindowRgn в обработчике события OnShow не работает, единственный способ - вызвать его, например, из таймера, установленного с интервалом 1. Включите таймер в Form.OnShow и отключите его в обработчике OnTimer.
Имитация событий мыши и ввода с клавиатуры
Имитировать ввод с помощью мыши и клавиатуры в LCL очень легко, просто используйте процедуры из модуля LCLMessageGlue, как это делают все интерфейсы widgetset. Этот модуль имеет процедуры, такие как:
unit LCLMessageGlue;
function LCLSendMouseMoveMsg(const Target: TControl; XPos, YPos: smallint;
ShiftState: TShiftState = []): PtrInt;
function LCLSendMouseDownMsg(const Target: TControl; XPos, YPos: smallint;
Button: TMouseButton; ShiftState: TShiftState = []): PtrInt;
function LCLSendMouseUpMsg(const Target: TControl; XPos, YPos: smallint;
Button: TMouseButton; ShiftState: TShiftState = []): PtrInt;
function LCLSendMouseWheelMsg(const Target: TControl; XPos, YPos, WheelDelta: smallint;
ShiftState: TShiftState = []): PtrInt;
function LCLSendCaptureChangedMsg(const Target: TControl): PtrInt;
function LCLSendSelectionChangedMsg(const Target: TControl): PtrInt;
function LCLSendClickedMsg(const Target: TControl): PtrInt;
function LCLSendMouseEnterMsg(const Target: TControl): PtrInt;
function LCLSendMouseLeaveMsg(const Target: TControl): PtrInt;
...
function LCLSendKeyDownEvent(const Target: TControl; var CharCode: word;
KeyData: PtrInt; BeforeEvent, IsSysKey: boolean): PtrInt;
function LCLSendKeyUpEvent(const Target: TControl; var CharCode: word;
KeyData: PtrInt; BeforeEvent, IsSysKey: boolean): PtrInt;
Показ виртуальной клавиатуры в смартфоне/планшете
Чтобы показать виртуальную клавиатуру, когда виджет получает фокус, в ControlStyle просто добавьте csRequiresKeyboardInput:
constructor TMyTextEditor.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
ControlStyle := ControlStyle + [csRequiresKeyboardInput];
...
end;
Перебор по всем дочерним элементам управления TWinControl
Это очень легко, просто используйте цикл для перебора TWinControl.ControlCount и TWinControl.Controls[Index]. Индекс начинается с нуля.
procedure TWinControl.WriteLayoutDebugReport(const Prefix: string);
var
i: Integer;
begin
inherited WriteLayoutDebugReport(Prefix);
for i:=0 to ControlCount-1 do
Controls[i].WriteLayoutDebugReport(Prefix+' ');
end;