Difference between revisions of "Lazarus For Delphi Users/ru"

From Lazarus wiki
Jump to navigationJump to search
 
(14 intermediate revisions by 2 users not shown)
Line 12: Line 12:
 
* Linux (i386, x86_64)
 
* Linux (i386, x86_64)
 
* FreeBSD (i386)
 
* FreeBSD (i386)
* Mac OS X (powerpc, i386)
+
* macOS (powerpc, i386, x86_64)
 
* Windows (i386, x86_64)
 
* Windows (i386, x86_64)
 
'''Работа над Lazarus, как и над этим текстом, не закончена. Мы всё время ищем новых разработчиков и технических писателей...'''
 
'''Работа над Lazarus, как и над этим текстом, не закончена. Мы всё время ищем новых разработчиков и технических писателей...'''
 +
 
=== С чего начать перенос проекта Delphi в Lazarus ===
 
=== С чего начать перенос проекта Delphi в Lazarus ===
 
В меню '''Сервис''' выберите команду '''Преобразовать проект Delphi в проект Lazarus'''. Не стоит ждать, что так будет преобразовано абсолютно всё, тем не менее, это хорошее начало. Учтите, что средства Lazarus выполняют, в основном, преобразования в одном направлении. Если вам надо сохранить совместимость с Delphi (компилировать проект и в Delphi, и в Lazarus) рассмотрите использование [[XDev Toolkit]].
 
В меню '''Сервис''' выберите команду '''Преобразовать проект Delphi в проект Lazarus'''. Не стоит ждать, что так будет преобразовано абсолютно всё, тем не менее, это хорошее начало. Учтите, что средства Lazarus выполняют, в основном, преобразования в одном направлении. Если вам надо сохранить совместимость с Delphi (компилировать проект и в Delphi, и в Lazarus) рассмотрите использование [[XDev Toolkit]].
Line 132: Line 133:
  
 
== VCL -> LCL ==
 
== VCL -> LCL ==
While the VCL and the LCL both serve much of the same purpose - of an Object Oriented Component Hierarchy especially geared toward rapid application development, they are not identical. For instance while the VCL provides many non-visual components, the LCL tries to only provide visual, while most non-visual components (such as db access) are provided by the FCL, included with [[Free Pascal]] .
+
Хотя VCL и LCL служат большей части одной и той же цели - объектно-ориентированной иерархии компонентов, особенно ориентированной на быструю разработку приложений, они не идентичны. Например, в то время как VCL предоставляет много невизуальных компонентов, LCL пытается предоставлять только визуальные, в то время как большинство невизуальных компонентов (таких как доступ к базе данных) предоставляются с FCL, включенным в [[Free Pascal]].
  
Additionally many controls may not exist in the LCL that are in the VCL, or vice versa, or even when controls do exist in both, they are not clones, and changes must be made in applications, components and controls if porting.
+
Кроме того, многие элементы управления, которые представлены в VCL, могут отсутствовать в LCL, или наоборот, или даже если элементы управления существуют в обоих, они не являются клонами, и при переносе необходимо внести изменения в приложения, компоненты и элементы управления.
  
The following is an attempt to provide fairly complete descriptions of major differences or incompatiblities between the two for the Delphi user. It covers differences primarily with the VCL of D4 especially, though at times D5, D6, or D7 as well; and with the current LCL, as is in CVS. As such it may not always be accurate to the version of Delphi you are used to, or completely match the current LCL you have. If you see inacuracies between the following and the LCL as in CVS, or your Delphi feel free to append and modify so as to keep this as comprehensive as possible for all people.
+
Ниже приведена попытка для пользователя Delphi дать достаточно полное описание основных различий или несовместимостей между ними. Она охватывает различия в первую очередь особенно для VCL D4, хотя иногда также D5, D6 или D7; и с текущим LCL, как в CVS. Таким образом, оно может не всегда соответствовать версии Delphi, к которой вы привыкли, или полностью соответствовать текущему LCL, который у вас есть. Если вы видите неточности между нижеследующим и LCL, как в CVS, или ваш Delphi не стесняется добавлять и изменять, чтобы сделать его максимально полным для всех людей.
  
 
=== TControl.Font/TControl.ParentFont ===
 
=== TControl.Font/TControl.ParentFont ===
In the VCL it is quite common and normal to use a specific font name and font properties such as bold and italics for controls, and expect this value to always be followed. Further is provided the TControl.ParentFont property which ensures that a control will always follow its parent's font. Again the implicit assumption being that these values will always be followed, even regardless of Windows Apearance Settings.  
+
В VCL довольно распространено и нормально использовать определенное имя шрифта и свойства шрифта, такие как жирный шрифт и курсив для элементов управления, и ожидать, что это значение всегда будет соблюдаться. Далее предоставляется свойство TControl.ParentFont, которое гарантирует, что элемент управления всегда будет следовать за шрифтом его родителя. Опять же подразумеваемое предположение, что эти значения будут всегда соблюдаться, даже независимо от настроек внешнего вида Windows.
  
This is not always true in the LCL, nor can it be. The LCL being cross-platform/cross-interface in nature prefers to take a balanced aproach, and instead will always try to use native Desktop/Toolkit Apearance or Theme settings on any widgets. For example if using a GTK interface, and the gtk theme supplies a specific font for buttons, then LCL buttons will always try to use this font.  
+
Это не всегда верно в LCL, да и не может быть. LCL, являющийся кросс-платформой/кросс-интерфейсом по своей природе, предпочитает сбалансированный подход и вместо этого всегда будет пытаться использовать собственные настройки Рабочего стола/Внешнего вида инструментария или Темы для любых виджетов. Например, если используется интерфейс GTK, а тема gtk предоставляет определенный шрифт для кнопок, то кнопки LCL всегда будут пытаться использовать этот шрифт.
  
This means that most LCL controls do not have the same level of design control that is often expected in the VCL, rather only those custom controls which are Canvas drawn instead of interface allocated can consistantly be modified in this manner regardless of the Interface used.
+
Это означает, что большинство элементов управления LCL не имеют того же уровня управления проектированием, который часто ожидается в VCL, скорее, только те пользовательские элементы управления, которые нарисованы Canvas вместо назначенного интерфейса, могут постоянно изменяться таким образом независимо от используемого интерфейса.
  
 
=== Control Dragging/Docking ===
 
=== Control Dragging/Docking ===
In the VCL most (Win)Controls implement methods and callback functions for handling dragging and docking of controls, eg. dragging a control from one panel, and docking it onto another panel at run time.  
+
В VCL большинство (Win)Controls реализуют методы и функции обратного вызова для обработки перетаскивания и закрепления элементов управления, например, перетаскивая элемент управления с одной панели и закрепляя его на другой панели во время выполнения.
  
This functionality is currently unimplemented/unfinished in the LCL, though it is currently in the initial stages of planning, and should eventually support some level of compatibility for this type of behavior, if not in the exact same manner.  
+
Эта функциональность в настоящее время не реализована/не завершена в LCL, хотя в настоящее время она находится на начальных этапах планирования и должна в конечном итоге поддерживать некоторый уровень совместимости для этого типа поведения, если не точно таким же образом.
  
This currently means that no Control will inherit/use the following TControl functions, procedures, properties, or events  -
+
В настоящее время это означает, что ни один элемент управления не будет наследовать/использовать следующие функции, процедуры, свойства или события TControl:
<syntaxhighlight>Protected
+
<syntaxhighlight lang=pascal>Protected
 
   function GetDockEdge(MousePos: TPoint): TAlign;
 
   function GetDockEdge(MousePos: TPoint): TAlign;
 
   function GetDragImages: TDragImageList;
 
   function GetDragImages: TDragImageList;
Line 199: Line 200:
 
   property UndockWidth: Integer;</syntaxhighlight>
 
   property UndockWidth: Integer;</syntaxhighlight>
  
that the following classes do not exist/are unusable -
+
Вот эти классы не существуют/непригодны для использования -
  
<syntaxhighlight>TDragImageList = class(TCustomImageList)
+
<syntaxhighlight lang=pascal>TDragImageList = class(TCustomImageList)
 
TDockZone = class
 
TDockZone = class
 
TDockTree = class(TInterfacedObject, IDockManager)
 
TDockTree = class(TInterfacedObject, IDockManager)
Line 209: Line 210:
 
TDragDockObject = class(TBaseDragControlObject) </syntaxhighlight>
 
TDragDockObject = class(TBaseDragControlObject) </syntaxhighlight>
  
and that the following functions are also unusable/incompatible -
+
а вот эти функции также непригодны / несовместимы -
  
<syntaxhighlight>function FindDragTarget(const Pos: TPoint;
+
<syntaxhighlight lang=pascal>function FindDragTarget(const Pos: TPoint;
 
                         AllowDisabled: Boolean) : TControl;
 
                         AllowDisabled: Boolean) : TControl;
 
procedure CancelDrag;
 
procedure CancelDrag;
 
function IsDragObject(sender: TObject): Boolean;</syntaxhighlight>
 
function IsDragObject(sender: TObject): Boolean;</syntaxhighlight>
  
The start of docking manager is described here: [[Anchor Docking]]
+
Запуск менеджера пристыковки окон описан здесь: [[Anchor Docking]]
  
 
=== TEdit/TCustomEdit ===
 
=== TEdit/TCustomEdit ===
The Edit controls, while functioning essentialy the same in the LCL as the VCL, do have some issues to be aware of in converting -
+
Элементы управления Edit, хотя они и функционируют в основном как в LCL, так и в VCL, имеют некоторые особенности, которые необходимо учитывать при преобразовании:
# Due to restrictions in the Interfaces, TEdit.PasswordChar does not work in all interfaces yet(though in time it may), instead TCustomEdit.EchoMode emPassword should be used in the event text needs to be hidden.
+
# Из-за ограничений в интерфейсах TEdit.PasswordChar работает пока не во всех интерфейсах (хотя со временем может и будет), вместо этого следует использовать TCustomEdit.EchoMode emPassword в том случае, если текст события должен быть скрыт.
# On Drag/Dock Events are not yet implemented. For more information please see earlier section on [[#Control Dragging/Docking | Control Dragging/Docking]].
+
# Событие Drag/Dock еще не реализовано. Для получения дополнительной информации см. предыдущий раздел [[#Control Dragging/Docking | Control Dragging/Docking]].
# Font Properties are usually ignored for interface consistancy, for detailed explanation as too why please see [[#TControl.Font/TControl.ParentFont | TControl.Font/TControl.ParentFont]]
+
# Свойства шрифта обычно игнорируются для согласованности интерфейса, для подробного объяснения, что и как, пожалуйста, см. [[#TControl.Font/TControl.ParentFont | TControl.Font/TControl.ParentFont]]
  
 
=== TDBImage ===
 
=== TDBImage ===
Delphi and Lazarus both have a [[TDBImage]] control that shows images stored in a database field. In current stable versions (1.2.4), Lazarus stores information about the image type in the database field before the actual image data. See procedure ''TDBImage.UpdateData''
+
Delphi и Lazarus имеют элемент управления [[TDBImage]], который показывает изображения, хранящиеся в поле базы данных. В текущих стабильных версиях (1.2.4) Lazarus хранит информацию о типе изображения в поле базы данных перед фактическими данными изображения. См. процедуру ''TDBImage.UpdateData''.
This means that Delphi and older Lazarus implementations are not compatible.  
+
Это означает, что Delphi и более старые реализации Lazarus не совместимы.
 +
 
 +
В текущей стабильной версии Lazarus (1.2.0+) реализованы изменения, позволяющие использовать поведение, совместимое с Delphi. Пожалуйста, см. [[Lazarus_1.2.0_release_notes#TDBImage]] для получения подробной информации о том, как активировать это.
 +
 
 +
Текущий транк Lazarus'а возвращается к Delphi-совместимому поведению при чтении полей базы данных в формате Delphi в TDBImage.
  
Current stable Lazarus (1.2.0+) has implemented changes that allow Delphi compatible behaviour. Please see [[Lazarus_1.2.0_release_notes#TDBImage]] for details on how to activate this.
+
=== (необязательно) TSplitter -> TPairSplitter ===
 +
'''Пожалуйста, улучшите меня!'''
  
Current Lazarus trunk falls back to Delphi-compatible behaviour on reading Delphi-formatted database fields into TDBImage.
+
Теперь в LCL есть элемент управления [[TSplitter/ru|TSplitter]], поэтому нет необходимости его преобразовывать.
  
=== (optional) TSplitter -> TPairSplitter ===
+
Тем не менее, если вы хотите, здесь приводится объяснение:
'''Please Improve Me'''
 
  
There is now a [[TSplitter]] control in the LCL, so no need to convert it.
+
Следующее в основном основано на вопросах пользователя [[User:Vincent | Vincent Snijders]] в списках рассылки и ответов [http://lazarus-ccr.sourceforge.net/index.php?wiki=AndrewJohnson Andrew Johnson]:
  
Nevertheless, if you want, here it is explained:
+
В VCL элементы управления "Splitting" - это ползунок, который можно перетаскивать между двумя компонентами для предоставления большего или меньшего пространства одному из них за счет другого; выполняется [посредством компонента] TSplitter. Например, в IDE Delphi его можно увидеть между закрепленным Code Explorer и Source Viewer.
  
The following is loosely based on questions by [[User:Vincent | Vincent Snijders]] on the mailing list, and responses by [http://lazarus-ccr.sourceforge.net/index.php?wiki=AndrewJohnson Andrew Johnson]:
+
LCL предоставляет свой собственный элемент управления, называемый [[TPairSplitter/ru|TPairSplitter]], который служит для тех же целей, однако он не совместим с Delphi, поэтому в случае переноса кода потребуется исправление "поврежденного" кода VCL или DFM-файлов Delphi, даже если используется много общего между двумя этими компонентами.
  
In the VCL, "Splitting" controls, that is a handle which can be dragged between two components to give one more or less space then the other, is accomplished by a TSplitter. This is often seen, for instance in the Delphi IDE between the docked Code Explorer and Source Viewer.
+
;Так в чем именно различия?
  
The LCL provides its own Control called a TPairSplitter, which serves the same type of purpose, however it is not compatible, so "repairing" broken VCL code or  Delphi DFM's will be necessary in the event of porting code, even though much is shared in common between the two.
+
Ну, самые большие различия в том, что VCL TSplitter не имеет [размещенных на нем] дочерних элементов, вместо этого он помещается между двумя правильно выровненными элементами управления и позволяет изменять их размер во время выполнения независимо от его собственного размера. На каждой стороне должно быть два элемента управления, чтобы что-нибудь сделать. Простым примером будет форма с выровненной по левому краю панелью, выровненным по левому краю разделителем и второй выровненной по клиенту панелью. Во время выполнения вы можете затем изменить размер, заданный для каждой панели, перетаскивая за специальный ползунок, предоставляемый элементом управления Splitter.
  
;So what exactly are the differences?
+
Однако с точки зрения LCL, TPairSplitter - это особый вид управления с двумя панелями, и он может быть полезен только в том случае, если элементы управления для разделения находятся на этих панелях, но он все равно будет выполнять разбиение между этими панелями, независимо от того, что расположено на них. Таким образом, по аналогии с  предыдущим примером, вы получите форму с выровненным клиентом TPairSplitter, выровненным по панели клиентом с левой стороны и выровненным по панели клиентом с правой стороны.
  
Well the biggest differences are a VCL TSplitter has no children, instead it is placed between two controls aligned properly, and allows resizing between them at runtime, regardless its own size. It must have two controls aligned on each side to do anything. A simple example would be form with a Left Aligned Panel, a left aligned Splitter, and a second client aligned panel. On run time you could then realign the size given each panel by dragging on the handle provided by this Splitter control.
+
----
 +
[[User:Zoltanleo|Прим.перев.]]: иными словами, TPairSplitter - это готовый контейнер, разделенный TSplitter на две половины (в зависимости от значения свойства SplitterType на левую/правую или верхнюю/нижнюю), каждая из которых уже имеет привязку alClient, готова принимать на себя дочерние элементы и меняет свои размеры при перемещении ползунка разделителя.
 +
----
  
On the LCL hand however, a TPairSplitter is a special kind of control, with two panels, and it can only be usefull if the controls to split are on these panels, but it will still perform a split between those panel whether or not anything is on them. So following the prior example, you would have a form with a TPairSplitter aligned client, and a panel aligned client on its left side, and a panel aligned client on its right side.
+
Другое важное отличие состоит в том, что в VCl, поскольку TSplitter является собственным TControl, положение сохраняется относительно других элементов управления при изменении размера. Поэтому, например, клиентская панель будет расти, в то время как другие панели этого делать не будут, таким образом, позиция разделения является относительна к выравниванию разделяемых элементов управления.
  
The other important difference is that in the VCl, since the TSplitter is its own TControl, then the position is kept relative to the other controls on resize, so for instance a client panel will grow while the other panels will not, thus the split position is relative to the alignment of the split controls,
+
В LCL, поскольку боковые панели отделены друг от друга, у TPairSplitter есть свойство Position, которое является абсолютным по отношению к верхнему или левому краям [родительского элемента]. Поэтому при изменении размера фактическая позиция не изменяется в зависимости от содержимого, отсюда, необходимо установить обратный вызов, чтобы обеспечить сохранение соотношения при изменении размера, если это важно.
  
In the LCL since the side panels are separate then the TPairSplitter has a Position property which is absolute relative to top or left. so on resize the actual position does not change according to contents, so a callback must be set to ensure the ratio is kept on resize if this is important.
+
----
 +
[[User:Zoltanleo|Прим.перев.]]: проще говоря, Position - это позиция ползунка TPairSplitter относительно левого/верхнего края контейнера (в зависимости от значения SplitterType = pstHorizontal/pstVertical соответственно).
 +
----
  
For example if the Right side of a vertical split needs to have alClient like behaviour, you need to add a form resize callback which does something like :
+
Например, если правая сторона вертикального разбиения должна иметь поведение, аналогичное alClient, необходимо добавить обратный вызов изменения размера формы, который выполняет что-то вроде:
PairSplitter.Position := PairSplitter.Width - PairSplitter.Position;  
+
<syntaxhighlight lang=pascal> PairSplitter.Position := PairSplitter.Width - PairSplitter.Position;</syntaxhighlight >
  
;So how can I convert existing code using TSplitter to the TPairSplitter?
+
;Итак, как я могу преобразовать существующий код, использующий TSplitter, в TPairSplitter?
  
If the splitter and controls are created within an actual function(like form oncreate), conversion shouldn't be too difficult, primarily reorganize the code to create the controls in order of new hierarchy and set the parents of the child controls to split to the left/top and right/bottom portions of the PairSplitter. An example  of the changes being -
+
Если разделитель и элементы управления создаются внутри фактической функции (например, при создании формы), преобразование не должно быть слишком сложным, в первую очередь реорганизуйте код, чтобы создать элементы управления в порядке новой иерархии, и установите родительские элементы дочерних элементов управления для разделения на левую/верхнюю и правую/нижнюю части PairSplitter. Пример изменений:
  
 
{| class="code"
 
{| class="code"
Line 267: Line 276:
 
|- class="code"
 
|- class="code"
 
| class="code" |
 
| class="code" |
<syntaxhighlight>var  
+
<syntaxhighlight lang=pascal>var  
 
   BottomPanel: TPanel;
 
   BottomPanel: TPanel;
 
   VerticalSplitter: TSplitter;
 
   VerticalSplitter: TSplitter;
Line 310: Line 319:
 
     Parent:= Self;
 
     Parent:= Self;
 
     Align:= alClient;
 
     Align:= alClient;
     Caption:= 'Hello';
+
     Caption:= 'Привет';
 
   end;
 
   end;
 
end;</syntaxhighlight>
 
end;</syntaxhighlight>
 
| class="code" |  
 
| class="code" |  
<syntaxhighlight>var
+
<syntaxhighlight lang=pascal>var
 
   BottomPanel: TPanel;
 
   BottomPanel: TPanel;
 
   VerticalSplitter: TPairSplitter;
 
   VerticalSplitter: TPairSplitter;
Line 358: Line 367:
 
     Parent:= HorizontalSplitter.Sides[1];
 
     Parent:= HorizontalSplitter.Sides[1];
 
     Align:= alClient;
 
     Align:= alClient;
     Caption:= 'Hello';
+
     Caption:= 'Привет';
 
   end;
 
   end;
  
Line 370: Line 379:
 
|}
 
|}
  
So as you can see, farely consistant with most control hierarchy. And if you are familiar with DFM's, the changes needed for DFM->LFM conversion should be farely obvious from the above, as they are the same sort of changes in Parent/Owner etc.
+
Таким образом, как вы видите, [преобразование] справедливо для большей [части кода] с [сохранением] иерархии элементов управления. И если вы знакомы со [структурой] DFM-файлов, изменения, необходимые для преобразования DFM -> LFM, должны быть очевидны из выше приведенного, поскольку они являются такими же изменениями в Parent/Owner и т.д.
  
So the above example would be something like -
+
Таким образом, приведенный выше пример будет что-то вроде -
  
 
{| class="code"
 
{| class="code"
 
|-  
 
|-  
| class="header" | '''Delphi DFM''' <div style="font-weight: normal">'''(extraneous values removed)'''
+
| class="header" | '''Delphi DFM''' <div style="font-weight: normal">'''(посторонние значения удалены)'''
| class="header" | '''Lazarus LFM''' <div style="font-weight: normal">'''(most width, height, etc. removed)'''
+
| class="header" | '''Lazarus LFM''' <div style="font-weight: normal">'''(большинство свойств width, height... и т.д. удалены)'''
 
|- class="code"
 
|- class="code"
 
| class="code" |
 
| class="code" |
<syntaxhighlight>object VerticalSplitter: TSplitter
+
<syntaxhighlight lang=pascal>object VerticalSplitter: TSplitter
 
   Height = 3
 
   Height = 3
 
   Cursor = crVSplit
 
   Cursor = crVSplit
Line 401: Line 410:
 
end</syntaxhighlight>
 
end</syntaxhighlight>
 
| class="code" |
 
| class="code" |
<syntaxhighlight>object VerticalSplitter: TPairSplitter
+
<syntaxhighlight lang=pascal>object VerticalSplitter: TPairSplitter
 
   Align = alClient
 
   Align = alClient
 
   SplitterType = pstVertical
 
   SplitterType = pstVertical
Line 435: Line 444:
  
 
=== TCustomTreeView/TTreeView ===
 
=== TCustomTreeView/TTreeView ===
Both VCL and the LCL provide a TCustomTreeView/TTreeView component, used for tree structured lists of data with multiple nodes and advanced selection and Image lists, and while actual features are comparable, not all properties are entirely compatible. Primary differences are as follows -
+
И VCL, и LCL предоставляют компонент TCustomTreeView/TTreeView, используемый для древовидных списков данных с несколькими узлами, расширенного выбора и списков изображений, и хотя фактические функции сопоставимы, не все свойства полностью совместимы. Основные различия заключаются в следующем -
 
 
'''Incomplete list, also update to include TCustomTreeView Mark functions and protected methods '''
 
  
#  The LCL provides a TCustomTreeView.Options, a set of options which can be set on the control to change its behaviour and apearance. These options are :
+
'''Список не полон, но обновлен для включения в него функции TCustomTreeView Mark и protected-методов'''
#* tvoAllowMultiselect - enables multi node select mode, equivalent to enabling TCustomTreeView.MultiSelect in the D6 VCL
 
#* tvoAutoExpand - Auto Expand nodes, equivalent to enabling TCustomTreeView.AutoExpand
 
#* tvoAutoInsertMark - Update the Drag preview on mouse move.
 
#* tvoAutoItemHeight - Adjust the item heights automatically.
 
#* tvoHideSelection - Do not mark the selected item.
 
#* tvoHotTrack  - use Hot Tracking, equivalent to enabling TCustomTreeview.HotTrack
 
#* tvoKeepCollapsedNodes - When shrinking/folding nodes, keep the child nodes
 
#* tvoReadOnly - make Treeview read only, equivalent to enabling TCustomTreeview.ReadOnly
 
#* tvoRightClickSelect - allow using Mouse Right Clicks to select nodes, equivalent to enabling TCustomTreeView.RightClickSelect
 
#* tvoRowSelect  - allow selecting rows, equivalent to enabling TCustomTreeView.RowSelect
 
#* tvoShowButtons  - show buttons, equivalent to enabling TCustomTreeView.ShowButtons
 
#* tvoShowLines - show node lines, equivalent to enabling TCustomTreeView.ShowLines
 
#* tvoShowRoot  - show root note, equivalent to enabling TCustomTreeView.ShowRoot
 
#* tvoShowSeparators  - show seperators
 
#* tvoToolTips - show tooltips for individual nodes
 
# The LCL provides additional properties:
 
#* TCustomTreeView.OnSelectionChange event
 
#* TCustomTreeView.DefaultItems, for the default number of Items
 
#* TCustomTreeView.ExpandSignType to determine sign used on expandable/collapsible nodes
 
# While most On Drag/Dock Events are available in the LCL they do not work. For more information please see earlier section on Control Dragging/Docking.
 
  
=== Messages / Events ===
+
# LCL предоставляет TCustomTreeView.Options, набор опций, которые можно установить в элементе управления, чтобы изменить его поведение и внешний вид. Вот эти опции:
 +
#* tvoAllowMultiselect - включает режим выбора нескольких узлов, эквивалентный включению TCustomTreeView.MultiSelect в VCL D6
 +
#* tvoAutoExpand - автоматическое раскрытие узлов, что эквивалентно включению TCustomTreeView.AutoExpand
 +
#* tvoAutoInsertMark - обновляет предосмотр Drag при перемещении мышью.
 +
#* tvoAutoItemHeight - автоматически регулирует высоту элемента.
 +
#* tvoHideSelection - не помечать выбранный элемент.
 +
#* tvoHotTrack  - использовать Hot Tracking, что эквивалетно включению TCustomTreeview.HotTrack
 +
#* tvoKeepCollapsedNodes - сохранять дочерние узлы при их сжатии/сворачивании
 +
#* tvoReadOnly - сделать Treeview доступным только для чтения, эквивалентно включению TCustomTreeview.ReadOnly
 +
#* tvoRightClickSelect - разрешить использовать правую кнопку мыши для выбора узлов, что эквивалентно включению TCustomTreeView.RightClickSelect
 +
#* tvoRowSelect  - разрешить выбор строк, что эквивалентно включению TCustomTreeView.RowSelect
 +
#* tvoShowButtons  - показывать кнопки, что эквивалентно включению TCustomTreeView.ShowButtons
 +
#* tvoShowLines - показывать линии узлов, что эквивалентные включению TCustomTreeView.ShowLines
 +
#* tvoShowRoot  - показывать корневые элементы, что эквивалентные включению TCustomTreeView.ShowRoot
 +
#* tvoShowSeparators  - показывать разделитель
 +
#* tvoToolTips - показывать подсказки для отдельных узлов
 +
# LCL предоставляет дополнительные свойства:
 +
#* Событие TCustomTreeView.OnSelectionChange
 +
#* TCustomTreeView.DefaultItems, для количества элементов [дерева] по умолчанию
 +
#* TCustomTreeView.ExpandSignType для определения знака, используемого в раскрывающихся/сворачивающихся узлах
 +
# Хотя большинство событий OnDrag/OnDock доступны в LCL, они не работают. Для получения дополнительной информации см. предыдущий раздел [[Lazarus_For_Delphi_Users/ru#Control_Dragging.2FDocking|Control Dragging/Docking]].
  
The order and frequency of messages and events (OnShow, OnActivate, OnEnter, ...) differ from the VCL and depend on the [[Widgetset|widgetset]].
+
=== Сообщения / События ===
The LCL provides a subset of WinAPI like messages to make porting of Delphi components easier, but almost all LCL messages work a little bit different than the VCL/WinAPI counterpart. The biggest part of Delphi code using WinAPI messages uses them, because the VCL lacks a feature or for speed reasons. Such things will seldom work the same under the LCL, so they must be checked manually. That's why LCL messages are called for example LM_SIZE instead of WM_SIZE (unit lmessages).
 
  
'''Note on handling of custom messages!'''
+
Порядок и частота сообщений и событий (OnShow, OnActivate, OnEnter, ...) отличаются от VCL и зависят от [[Widgetset | widgetset]].
As of version 0.9.26 (December 2008), way of handling custom WinApi messages (e.g. WM_HOTKEY, WM_SYSCOMMAND) differs from the way of handling these messages in Delphi. At the moment you cannot handle them via '''message''' directive or via overriding of ''WndProc'' method of the form. The only way to handle them in the form is to hook Windows ''windowproc'' by yourself. Read more here: [[Win32/64_Interface#Processing_non-user_messages_in_your_window | Processing non-user messages in your window]]
+
LCL предоставляет подмножество WinAPI-подобных сообщений, чтобы упростить перенос компонентов Delphi, но почти все сообщения LCL работают несколько иначе, чем аналоги VCL/WinAPI. Большая часть кода Delphi, использующего сообщения WinAPI, использует их, потому что VCL не имеет функции или по соображениям скорости. Такие вещи редко работают одинаково в LCL, поэтому их нужно проверять вручную. Вот почему сообщения LCL называются, например, LM_SIZE вместо WM_SIZE (модуль Lmessages).
  
==See Also==
+
'''Замечание по обработке пользовательских сообщений!'''
 +
Начиная с версии 0.9.26 (декабрь 2008г.), способ обработки пользовательских сообщений WinApi (например, WM_HOTKEY, WM_SYSCOMMAND) отличается от способа обработки этих сообщений в Delphi. В настоящее время вы не можете обработать их с помощью директивы '''message''' или переопределением метода ''WndProc'' формы. Единственный способ обработать их в форме - это самому перехватить сообщение Windows ''windowproc''. Подробнее читайте здесь: [[Win32/64_Interface#Processing_non-user_messages_in_your_window | Processing non-user messages in your window]]
  
* [[Code Conversion Guide| Code Conversion Guide (from Delphi & Kylix)]]
+
==См. также==
* [[Compile With Delphi]]
 
  
[[Category:Tutorials]]
+
* [[Code_Conversion_Guide/ru| Code Conversion Guide (from Delphi & Kylix)]]
[[Category:Delphi]]
+
* [[Compile_With_Delphi/ru|Compile With Delphi]]
[[Category:Lazarus]]
 
[[Category:Lazarus internals]]
 

Latest revision as of 03:18, 22 December 2019

Deutsch (de) English (en) español (es) français (fr) 日本語 (ja) 한국어 (ko) português (pt) русский (ru) slovenčina (sk)

Эта статья предназначена для тех, кто интересуется Lazarus и уже знает Delphi. Здесь описаны различия между ними.

Delphi -> Lazarus

Lazarus - среда быстрой разработки приложений (RAD), как и Delphi. Это значит, что она состоит из библиотеки визуальных компонентов и среды разработки (IDE). Библиотека компонентов Lazarus (LCL) похожа на библиотеку визуальных компонентов Delphi (VCL). Большинство модулей, классов и свойств Lazarus обладают такими же именами и функциями, как их аналоги в Delphi. Это делает относительно лёгким перенос приложений Delphi в Lazarus. Однако Lazarus не является 'клоном Delphi с открытым кодом', поэтому не следует ожидать 100%-ной совместимости.

Самые большие различия между Lazarus и Delphi

  • код Lazarus полностью открыт
  • Lazarus написан кроссплатформенным способом
  • Lazarus использует компилятор Free Pascal (FPC)

FPC работает на 15 платформах. Однако не все пакеты и библиотеки FPC портированы на все платформы, поэтому Lazarus работает на:

  • Linux (i386, x86_64)
  • FreeBSD (i386)
  • macOS (powerpc, i386, x86_64)
  • Windows (i386, x86_64)

Работа над Lazarus, как и над этим текстом, не закончена. Мы всё время ищем новых разработчиков и технических писателей...

С чего начать перенос проекта Delphi в Lazarus

В меню Сервис выберите команду Преобразовать проект Delphi в проект Lazarus. Не стоит ждать, что так будет преобразовано абсолютно всё, тем не менее, это хорошее начало. Учтите, что средства Lazarus выполняют, в основном, преобразования в одном направлении. Если вам надо сохранить совместимость с Delphi (компилировать проект и в Delphi, и в Lazarus) рассмотрите использование XDev Toolkit.

Поддержка Юникода

Delphi до версии 2007 не поддерживала Юникод, а использовала кодировку Windows ANSI. Юникод в кодировке UTF-16 поддерживается в Delphi с версии 2009.

В Lazarus поддержка Юникод реализована раньше в кодировке UTF-8 (см. Поддержка Юникод в LCL).

Delphi IDE -> Lazarus IDE

Проекты

Главным в приложении Delphi является файл .dpr. Файл .dpr также содержит главный код программы Delphi и является местом, где среда разработки Delphi хранит сведения о соответствующих ключах компилятора и нахождении модулей. В приложении Lazarus есть файл .lpr, который также является основным файлом кода проекта на языке Pascal. Тем не менее, главным в проекте Lazarus является файл .lpi (Lazarus Project Information), который создаётся вместе с файлом .lpr. Все данные проекта (ключи компилятора, пути к модулям и т.п.) хранятся в файле .lpi. Поэтому важнейшим является файл .lpi. На большинстве платформ двойной щелчок по файлу .lpi открывает проект в среде разработки Lazarus.

Delphi хранит пути к модулям проекта в файле .dpr. Пример:

unit1 in 'path/Unit1.pas';

Такие пути со словом 'in' специфичны для Delphi, и не работают в Lazarus, поэтому не используйте их. Вместо этого в параметрах проекта (Проект->Параметры проекта...) на странице Параметры компилятора->Пути задайте пути к модулям, находящимся за пределами каталога проекта. Большинство путей к модулям задаются автоматически после добавления зависимости от какого-либо пакета. Например, во все стандартные проекты Lazarus LCL по умолчанию добавляется зависимость от пакета LCL, поэтому в каждом новом проекте Lazarus LCL (Проект->Создать проект...->Приложение) пути ко всем модулям LCL известны без вашего участия.

Delphi хранит параметры компилятора в файле .dpr (например, {$APPTYPE CONSOLE}). Lazarus игнорирует такую запись. Вместо этого используйте страницу Параметры компилятора в диалоге Параметры проекта.

Среда Lazarus не бывает "пустой"

В среде Lazarus всегда открыт проект. Единственный способ "закрыть" проект - выход из Lazarus или открытие другого проекта. Это связано с тем, что проект Lazarus - ещё и "сеанс работы". Сведения о сеансе (например, параметры редактора) также хранятся в файле .lpi, и при повторном открытии проекта состояние редактора восстанавливается.

Пример. Вы отлаживаете приложение и расставили несколько точек останова и закладок. Вы можете в любой момент сохранить проект, закрыть Lazarus или открыть другой проект. При повторном открытии проекта (даже на другом компьютере) все точки останова, закладки, открытые файлы, положение курсора, история переходов будут восстановлены.

Редактор исходного кода

В меню Сервис -> Параметры -> Редактор -> Комбинации клавиш могут быть заданы практически любые комбинации клавиш.

Среда разработки Lazarus располагает множеством инструментов для работы с кодом. Многие из них выглядят и работают так же, как и в Delphi. Но есть одно важное отличие: Lazarus не использует компилятор для получения сведений о коде, а работает с ним напрямую. Это даёт ряд важных преимуществ:

Редактор работает с "комментариями". В Delphi комментарии это просто место между фрагментами кода. Здесь не действуют никакие средства работы с кодом, и комментарии смещаются при автоматической вставке нового кода. В Lazarus можно найти объявление даже в закоментированном коде. Это не очень надёжно, однако работает в большинстве случаев. При вставке нового кода среда разработки использует некоторую эвристику, чтобы сохранить комментарий и код вместе. К примеру, строка "c: char; // comment" разделяться не будет.

Дельфийское «Автозавершение кода» (Ctrl + Space) в Lazarus называется «Автозавершение идентификатора». Термин Lazarus'овское «Автозавершение кода» - это функция, объединяющая «Автоматическое завершение класса» (как в Delphi), «Автозавершение локальной переменной» и «Автозавершение назначения события». Все они вызываются по Ctrl + Space + C, что подразумевает, что среда IDE определяет положение курсора.

Пример для автозавершения локальной переменной

Предположим, вы только что создали новый метод и написали оператор "i:=3;"

procedure TForm1.DoSomething;
begin
  i := 3;
end;

Наведите курсор на идентификатор «i» и нажмите Ctrl+ Shift+C, чтобы получить:

procedure TForm1.DoSomething;
var i: Integer;
begin
  i := 3;
end;

Пример автозавершения назначения события

Приятной особенностью инспектора объектов является автоматическое создание методов. Заодно, вы можете получить редактор исходного кода для создания событий.
Например:

Button1.OnClick:=

Поместите курсор за оператором присваивания ":=" и нажмите Ctrl+ Shift+C.


Прим.перев.: при этом сформированный код будет выглядеть так:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.OnClick:=@Button1Click;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin

end;

Пример автозавершения вызова процедуры

Предположим, вы только что написали оператор "DoSomething(Width);"

procedure SomeProcedure;
var
  Width: integer;
begin
  Width:=3;
  DoSomething(Width);
end;

Наведите курсор на идентификатор «DoSomething» и нажмите Ctrl+ Shift+C, чтобы получить:

procedure DoSomething(aWidth: LongInt);
begin

end;

procedure SomeProcedure;
var
  Width: integer;
begin
  Width:=3;
  DoSomething(Width);
end;

"Автозавершение слова" Ctrl+W

Он работает аналогично «Автозавершению идентификатора», но работает не для идентификаторов паскалей, а для всех слов. Позволяет выбрать все слова во всех открытых файлах, начиная с одинаковых букв.

Поддержка Include-файлов

Delphi не поддерживал их, поэтому вы, вероятно, еще не создавали много включаемых файлов. Но у включаемых файлов есть большое преимущество: они позволяют писать (не)зависимый от платформы код, не запутывая ваш код IFDEF'ами. Например: переход по методу, автозавершение класса, объявление find, ... все работает с include-файлами.

Есть много вариантов функций кода.

Designer

- см. руководство пользователя

Инспектор объектов

В IDE Delphi и IDE Lazarus'а Инспектор объектов используется для редактирования свойств компонента, назначения событий и т.д. Ниже приведены некоторые незначительные отличия, которые следует отметить при использовании:

  1. Начиная с Delphi 5, существует Дерево Объектов(Object Treeview), которое можно использовать для навигации и выбора объектов в соответствии с иерархией в дополнение к традиционному выпадающему списку в Инспекторе объектов. В Lazarus это является частью Инспектора объектов и используется вместо раскрывающегося списка по умолчанию, вы можете выбрать его из контекстного меню "Show Component Tree"(Показать дерево компонентов), чтобы использовать/не использовать.
  2. В Delphi двойной щелчок на пустом событии автоматически создаст его и откроет редактор исходного кода в этой позиции, в Lazarus справа от выбранного выпадающего меню есть кнопка, которая выполняет это действие.
  3. В Delphi вы должны вручную удалить имя события в редакторе, чтобы удалить привязку к нему, в Lazarus вы можете нажать на раскрывающийся список и выбрать "(None)"(Нет).
  4. Двойной щелчок по обычным свойствам, таким как логическое значение, не изменит его значение (как это произошло бы случае с Events(Событием)), вы должны выбрать его из выпадающего списка. А чтобы открыть их с прилагаемой формой редактора, вы должны нажать кнопку «...» справа от раскрывающегося меню.

Пакеты

  • Может ли Lazarus установить и использовать пакеты Delphi?
Нет, потому что они требуют магии компилятора Delphi.
  • Должны ли они быть специально сделанными для Lazarus?
Да.
Создайте новый пакет, сохраните его в каталоге с исходниками пакета (обычно это тот же каталог файла .dpk), добавьте LCL как требуемый пакет и, наконец, добавьте файлы .pas. Теперь вы можете установить его или использовать в своих проектах. Есть некоторые различия между пакетами Lazarus и Delphi.

VCL -> LCL

Хотя VCL и LCL служат большей части одной и той же цели - объектно-ориентированной иерархии компонентов, особенно ориентированной на быструю разработку приложений, они не идентичны. Например, в то время как VCL предоставляет много невизуальных компонентов, LCL пытается предоставлять только визуальные, в то время как большинство невизуальных компонентов (таких как доступ к базе данных) предоставляются с FCL, включенным в Free Pascal.

Кроме того, многие элементы управления, которые представлены в VCL, могут отсутствовать в LCL, или наоборот, или даже если элементы управления существуют в обоих, они не являются клонами, и при переносе необходимо внести изменения в приложения, компоненты и элементы управления.

Ниже приведена попытка для пользователя Delphi дать достаточно полное описание основных различий или несовместимостей между ними. Она охватывает различия в первую очередь особенно для VCL D4, хотя иногда также D5, D6 или D7; и с текущим LCL, как в CVS. Таким образом, оно может не всегда соответствовать версии Delphi, к которой вы привыкли, или полностью соответствовать текущему LCL, который у вас есть. Если вы видите неточности между нижеследующим и LCL, как в CVS, или ваш Delphi не стесняется добавлять и изменять, чтобы сделать его максимально полным для всех людей.

TControl.Font/TControl.ParentFont

В VCL довольно распространено и нормально использовать определенное имя шрифта и свойства шрифта, такие как жирный шрифт и курсив для элементов управления, и ожидать, что это значение всегда будет соблюдаться. Далее предоставляется свойство TControl.ParentFont, которое гарантирует, что элемент управления всегда будет следовать за шрифтом его родителя. Опять же подразумеваемое предположение, что эти значения будут всегда соблюдаться, даже независимо от настроек внешнего вида Windows.

Это не всегда верно в LCL, да и не может быть. LCL, являющийся кросс-платформой/кросс-интерфейсом по своей природе, предпочитает сбалансированный подход и вместо этого всегда будет пытаться использовать собственные настройки Рабочего стола/Внешнего вида инструментария или Темы для любых виджетов. Например, если используется интерфейс GTK, а тема gtk предоставляет определенный шрифт для кнопок, то кнопки LCL всегда будут пытаться использовать этот шрифт.

Это означает, что большинство элементов управления LCL не имеют того же уровня управления проектированием, который часто ожидается в VCL, скорее, только те пользовательские элементы управления, которые нарисованы Canvas вместо назначенного интерфейса, могут постоянно изменяться таким образом независимо от используемого интерфейса.

Control Dragging/Docking

В VCL большинство (Win)Controls реализуют методы и функции обратного вызова для обработки перетаскивания и закрепления элементов управления, например, перетаскивая элемент управления с одной панели и закрепляя его на другой панели во время выполнения.

Эта функциональность в настоящее время не реализована/не завершена в LCL, хотя в настоящее время она находится на начальных этапах планирования и должна в конечном итоге поддерживать некоторый уровень совместимости для этого типа поведения, если не точно таким же образом.

В настоящее время это означает, что ни один элемент управления не будет наследовать/использовать следующие функции, процедуры, свойства или события TControl:

Protected
  function GetDockEdge(MousePos: TPoint): TAlign;
  function GetDragImages: TDragImageList;
  function GetFloating: Boolean;
  function GetFloatingDockSiteClass: TWinControlClass;
  procedure DoEndDrag(Target:TObject); X, Y: Integer);
  procedure DockTrackNoTarget(Source: TDragDockObject; X, Y: Integer);
  procedure DoEndDock(Target: TObject; X, Y: Integer);
  procedure DoDock(NewDockSite: TWinControl; var ARect: TRect);
  procedure DoStartDock(var DragObject: TDragObject);
  procedure DragCanceled;
  procedure DragOver(Source: TObject; X, Y: Integer; State: TDragState;
                    var Accept: Boolean);
  procedure DoEndDrag(Target: TObject; X, Y: Integer);
  procedure DoStartDrag(var DragObject: TDragObject);
  procedure DrawDragDockImage(DragDockObject: TDragDockObject);
  procedure EraseDragDockImage(DragDockObject: TDragDockObject);
  procedure PositionDockRect(DragDockObject: TDragDockObject);
  procedure SetDragMode(Value: TDragMode);
  property DragKind: TDragKind;
  property DragCursor: TCursor;
  property DragMode: TDragMode;
  property OnDragDrop: TDragDropEvent;
  property OnDragOver: TDragOverEvent;
  property OnEndDock: TEndDragEvent;
  property OnEndDrag: TEndDragEvent;
  property OnStartDock: TStartDockEvent;
  property OnStartDrag: TStartDragEvent;
public
  function Dragging: Boolean;
  function ManualDock(NewDockSite: TWinControl; DropControl: TControl;
                     ControlSide: TAlign): Boolean;
  function ManualFloat(ScreenPos: TRect): Boolean;
  function ReplaceDockedControl(Control: TControl; NewDockSite: TWinControl;
                      DropControl: TControl; ControlSide: TAlign): Boolean;
  procedure BeginDrag(Immediate: Boolean; Threshold: Integer);
  procedure Dock(NewDockSite: TWinControl; ARect: TRect);
  procedure DragDrop(Source: TObject; X, Y: Integer);
  procedure EndDrag(Drop: Boolean);
  property DockOrientation: TDockOrientation;
  property Floating: Boolean;
  property FloatingDockSiteClass: TWinControlClass;
  property HostDockSite: TWinControl;
  property LRDockWidth: Integer;
  property TBDockHeight: Integer;
  property UndockHeight: Integer;
  property UndockWidth: Integer;

Вот эти классы не существуют/непригодны для использования -

TDragImageList = class(TCustomImageList)
TDockZone = class
TDockTree = class(TInterfacedObject, IDockManager)
TDragObject = class(TObject)
TBaseDragControlObject = class(TDragObject)
TDragControlObject = class(TBaseDragControlObject)
TDragDockObject = class(TBaseDragControlObject)

а вот эти функции также непригодны / несовместимы -

function FindDragTarget(const Pos: TPoint;
                         AllowDisabled: Boolean) : TControl;
procedure CancelDrag;
function IsDragObject(sender: TObject): Boolean;

Запуск менеджера пристыковки окон описан здесь: Anchor Docking

TEdit/TCustomEdit

Элементы управления Edit, хотя они и функционируют в основном как в LCL, так и в VCL, имеют некоторые особенности, которые необходимо учитывать при преобразовании:

  1. Из-за ограничений в интерфейсах TEdit.PasswordChar работает пока не во всех интерфейсах (хотя со временем может и будет), вместо этого следует использовать TCustomEdit.EchoMode emPassword в том случае, если текст события должен быть скрыт.
  2. Событие Drag/Dock еще не реализовано. Для получения дополнительной информации см. предыдущий раздел Control Dragging/Docking.
  3. Свойства шрифта обычно игнорируются для согласованности интерфейса, для подробного объяснения, что и как, пожалуйста, см. TControl.Font/TControl.ParentFont

TDBImage

Delphi и Lazarus имеют элемент управления TDBImage, который показывает изображения, хранящиеся в поле базы данных. В текущих стабильных версиях (1.2.4) Lazarus хранит информацию о типе изображения в поле базы данных перед фактическими данными изображения. См. процедуру TDBImage.UpdateData. Это означает, что Delphi и более старые реализации Lazarus не совместимы.

В текущей стабильной версии Lazarus (1.2.0+) реализованы изменения, позволяющие использовать поведение, совместимое с Delphi. Пожалуйста, см. Lazarus_1.2.0_release_notes#TDBImage для получения подробной информации о том, как активировать это.

Текущий транк Lazarus'а возвращается к Delphi-совместимому поведению при чтении полей базы данных в формате Delphi в TDBImage.

(необязательно) TSplitter -> TPairSplitter

Пожалуйста, улучшите меня!

Теперь в LCL есть элемент управления TSplitter, поэтому нет необходимости его преобразовывать.

Тем не менее, если вы хотите, здесь приводится объяснение:

Следующее в основном основано на вопросах пользователя Vincent Snijders в списках рассылки и ответов Andrew Johnson:

В VCL элементы управления "Splitting" - это ползунок, который можно перетаскивать между двумя компонентами для предоставления большего или меньшего пространства одному из них за счет другого; выполняется [посредством компонента] TSplitter. Например, в IDE Delphi его можно увидеть между закрепленным Code Explorer и Source Viewer.

LCL предоставляет свой собственный элемент управления, называемый TPairSplitter, который служит для тех же целей, однако он не совместим с Delphi, поэтому в случае переноса кода потребуется исправление "поврежденного" кода VCL или DFM-файлов Delphi, даже если используется много общего между двумя этими компонентами.

Так в чем именно различия?

Ну, самые большие различия в том, что VCL TSplitter не имеет [размещенных на нем] дочерних элементов, вместо этого он помещается между двумя правильно выровненными элементами управления и позволяет изменять их размер во время выполнения независимо от его собственного размера. На каждой стороне должно быть два элемента управления, чтобы что-нибудь сделать. Простым примером будет форма с выровненной по левому краю панелью, выровненным по левому краю разделителем и второй выровненной по клиенту панелью. Во время выполнения вы можете затем изменить размер, заданный для каждой панели, перетаскивая за специальный ползунок, предоставляемый элементом управления Splitter.

Однако с точки зрения LCL, TPairSplitter - это особый вид управления с двумя панелями, и он может быть полезен только в том случае, если элементы управления для разделения находятся на этих панелях, но он все равно будет выполнять разбиение между этими панелями, независимо от того, что расположено на них. Таким образом, по аналогии с предыдущим примером, вы получите форму с выровненным клиентом TPairSplitter, выровненным по панели клиентом с левой стороны и выровненным по панели клиентом с правой стороны.


Прим.перев.: иными словами, TPairSplitter - это готовый контейнер, разделенный TSplitter на две половины (в зависимости от значения свойства SplitterType на левую/правую или верхнюю/нижнюю), каждая из которых уже имеет привязку alClient, готова принимать на себя дочерние элементы и меняет свои размеры при перемещении ползунка разделителя.


Другое важное отличие состоит в том, что в VCl, поскольку TSplitter является собственным TControl, положение сохраняется относительно других элементов управления при изменении размера. Поэтому, например, клиентская панель будет расти, в то время как другие панели этого делать не будут, таким образом, позиция разделения является относительна к выравниванию разделяемых элементов управления.

В LCL, поскольку боковые панели отделены друг от друга, у TPairSplitter есть свойство Position, которое является абсолютным по отношению к верхнему или левому краям [родительского элемента]. Поэтому при изменении размера фактическая позиция не изменяется в зависимости от содержимого, отсюда, необходимо установить обратный вызов, чтобы обеспечить сохранение соотношения при изменении размера, если это важно.


Прим.перев.: проще говоря, Position - это позиция ползунка TPairSplitter относительно левого/верхнего края контейнера (в зависимости от значения SplitterType = pstHorizontal/pstVertical соответственно).


Например, если правая сторона вертикального разбиения должна иметь поведение, аналогичное alClient, необходимо добавить обратный вызов изменения размера формы, который выполняет что-то вроде:

 PairSplitter.Position := PairSplitter.Width - PairSplitter.Position;
Итак, как я могу преобразовать существующий код, использующий TSplitter, в TPairSplitter?

Если разделитель и элементы управления создаются внутри фактической функции (например, при создании формы), преобразование не должно быть слишком сложным, в первую очередь реорганизуйте код, чтобы создать элементы управления в порядке новой иерархии, и установите родительские элементы дочерних элементов управления для разделения на левую/верхнюю и правую/нижнюю части PairSplitter. Пример изменений:

VCL LCL
var 
  BottomPanel: TPanel;
  VerticalSplitter: TSplitter;
  LeftPanel: TPanel;
  HorizontalSplitter: TSplitter;
  MainPanel: TPanel;

begin
  BottomPanel:= TPanel.Create(Self);
  with (BottomPanel) do
  begin
    Parent:= Self;
    Height:= 75;
    Align:= alBottom;
  end;

  VerticalSplitter:= TSplitter.Create(Self);
  with (VerticalSplitter) do
  begin
    Parent:= Self;
    Align:= alBottom;
  end;

  HorizontalSplitter:= TSplitter.Create(Self);
  with (HorizontalSplitter) do
  begin
    Parent:= Self;
    align:= alLeft;
  end;

  LeftPanel:= TPanel.Create(Self);
  with (LeftPanel) do
  begin
    Parent:= Self;
    Width:= 125;
    Align:= alLeft;
  end;

  MainPanel:= TPanel.Create(Self);
  with (MainPanel) do
  begin
    Parent:= Self;
    Align:= alClient;
    Caption:= 'Привет';
  end;
end;
var
  BottomPanel: TPanel;
  VerticalSplitter: TPairSplitter;
  LeftPanel: TPanel;
  HorizontalSplitter: TPairSplitter;
  MainPanel: TPanel;

begin
  VerticalSplitter:= TPairSplitter.Create(Self);
  with (VerticalSplitter) do
  begin
    Parent:= Self;
    Align:= alClient;
    Width:= Self.Width;
    Height:= Self.Height;
    SplitterType:= pstVertical;
    Position:= Height - 75;
    Sides[0].Width:= Width;
    Sides[0].Height:= Position;
  end;

  HorizontalSplitter:= TPairSplitter.Create(Self);
  with (HorizontalSplitter) do
  begin
    Parent:= VerticalSplitter.Sides[0];
    Width:= Self.Width;
    Height:= VerticalSplitter.Position;
    align:= alClient;
    SplitterType:= pstHorizontal;
    Position:= 125;
  end;

  LeftPanel:= TPanel.Create(Self);
  with (LeftPanel) do
  begin
    Parent:= HorizontalSplitter.Sides[0];
    Align:= alClient;
  end;

  MainPanel:= TPanel.Create(Self);
  with (MainPanel) do
  begin
    Parent:= HorizontalSplitter.Sides[1];
    Align:= alClient;
    Caption:= 'Привет';
  end;

  BottomPanel:= TPanel.Create(Self);
  with (BottomPanel) do
  begin
    Parent:= VerticalSplitter.Sides[1];
    Align:= alClient;
  end;
end;

Таким образом, как вы видите, [преобразование] справедливо для большей [части кода] с [сохранением] иерархии элементов управления. И если вы знакомы со [структурой] DFM-файлов, изменения, необходимые для преобразования DFM -> LFM, должны быть очевидны из выше приведенного, поскольку они являются такими же изменениями в Parent/Owner и т.д.

Таким образом, приведенный выше пример будет что-то вроде -

Delphi DFM
(посторонние значения удалены)
Lazarus LFM
(большинство свойств width, height... и т.д. удалены)
object VerticalSplitter: TSplitter
  Height = 3
  Cursor = crVSplit
  Align = alBottom
end
object HorizontalSplitter: TSplitter
  Width = 3
  Align = alLeft
end
object BottomPanel: TPanel
  Height = 75
  Align = alBottom
end
object LeftPanel: TPanel
  Width = 125
  Align = alLeft
end
object MainPanel: TPanel
  Align = alClient
end
object VerticalSplitter: TPairSplitter
  Align = alClient
  SplitterType = pstVertical
  Position = 225
  Height = 300
  Width = 400
  object Pairsplitterside1: TPairSplitterIde
    object HorizontalSplitter: TPairSplitter
      Align = alClient
      Position = 125
      object Pairsplitterside3: TPairSplitterIde
        Width = 125
        object LeftPanel: TPanel
          Align = alClient
          Width = 125
        end
      end
      object Pairsplitterside4: TPairSplitterIde
        object MainPanel: TPanel
          Align = alClient
        end
      end
    end
  end
  object Pairsplitterside2: TPairSplitterIde
    object BottomPanel: TPanel
      Align = alClient
      Height = 75
    end
  end
end

TCustomTreeView/TTreeView

И VCL, и LCL предоставляют компонент TCustomTreeView/TTreeView, используемый для древовидных списков данных с несколькими узлами, расширенного выбора и списков изображений, и хотя фактические функции сопоставимы, не все свойства полностью совместимы. Основные различия заключаются в следующем -

Список не полон, но обновлен для включения в него функции TCustomTreeView Mark и protected-методов

  1. LCL предоставляет TCustomTreeView.Options, набор опций, которые можно установить в элементе управления, чтобы изменить его поведение и внешний вид. Вот эти опции:
    • tvoAllowMultiselect - включает режим выбора нескольких узлов, эквивалентный включению TCustomTreeView.MultiSelect в VCL D6
    • tvoAutoExpand - автоматическое раскрытие узлов, что эквивалентно включению TCustomTreeView.AutoExpand
    • tvoAutoInsertMark - обновляет предосмотр Drag при перемещении мышью.
    • tvoAutoItemHeight - автоматически регулирует высоту элемента.
    • tvoHideSelection - не помечать выбранный элемент.
    • tvoHotTrack - использовать Hot Tracking, что эквивалетно включению TCustomTreeview.HotTrack
    • tvoKeepCollapsedNodes - сохранять дочерние узлы при их сжатии/сворачивании
    • tvoReadOnly - сделать Treeview доступным только для чтения, эквивалентно включению TCustomTreeview.ReadOnly
    • tvoRightClickSelect - разрешить использовать правую кнопку мыши для выбора узлов, что эквивалентно включению TCustomTreeView.RightClickSelect
    • tvoRowSelect - разрешить выбор строк, что эквивалентно включению TCustomTreeView.RowSelect
    • tvoShowButtons - показывать кнопки, что эквивалентно включению TCustomTreeView.ShowButtons
    • tvoShowLines - показывать линии узлов, что эквивалентные включению TCustomTreeView.ShowLines
    • tvoShowRoot - показывать корневые элементы, что эквивалентные включению TCustomTreeView.ShowRoot
    • tvoShowSeparators - показывать разделитель
    • tvoToolTips - показывать подсказки для отдельных узлов
  2. LCL предоставляет дополнительные свойства:
    • Событие TCustomTreeView.OnSelectionChange
    • TCustomTreeView.DefaultItems, для количества элементов [дерева] по умолчанию
    • TCustomTreeView.ExpandSignType для определения знака, используемого в раскрывающихся/сворачивающихся узлах
  3. Хотя большинство событий OnDrag/OnDock доступны в LCL, они не работают. Для получения дополнительной информации см. предыдущий раздел Control Dragging/Docking.

Сообщения / События

Порядок и частота сообщений и событий (OnShow, OnActivate, OnEnter, ...) отличаются от VCL и зависят от widgetset. LCL предоставляет подмножество WinAPI-подобных сообщений, чтобы упростить перенос компонентов Delphi, но почти все сообщения LCL работают несколько иначе, чем аналоги VCL/WinAPI. Большая часть кода Delphi, использующего сообщения WinAPI, использует их, потому что VCL не имеет функции или по соображениям скорости. Такие вещи редко работают одинаково в LCL, поэтому их нужно проверять вручную. Вот почему сообщения LCL называются, например, LM_SIZE вместо WM_SIZE (модуль Lmessages).

Замечание по обработке пользовательских сообщений! Начиная с версии 0.9.26 (декабрь 2008г.), способ обработки пользовательских сообщений WinApi (например, WM_HOTKEY, WM_SYSCOMMAND) отличается от способа обработки этих сообщений в Delphi. В настоящее время вы не можете обработать их с помощью директивы message или переопределением метода WndProc формы. Единственный способ обработать их в форме - это самому перехватить сообщение Windows windowproc. Подробнее читайте здесь: Processing non-user messages in your window

См. также