Difference between revisions of "How To Write Lazarus Component/ru"

From Free Pascal wiki
Jump to navigationJump to search
m (Fixed syntax highlighting; deleted category included in page template)
 
(41 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{How_To_Write_Lazarus_Component/ru}}
+
{{How_To_Write_Lazarus_Component}}
  
  
----
+
Это руководство по созданию компонентов.
<span style="color:#FF0000">ENG: '''AT THE MOMENT THIS PAGE IS UNDER TRANSLATION.''' <br /> RUS: '''В НАСТОЯЩИЙ МОМЕНТ СТРАНИЦА НАХОДИТСЯ В ПРОЦЕССЕ ПЕРЕВОДА.'''</span>
 
----
 
 
 
  
This is a guide on how to build components.
+
__TOC__
  
==Step 1: Create the package==
+
==Шаг 1: Создание пакета==
  
* On the Lazarus IDE menu, click '''Package > New Package''' to run the Package Manager.  
+
* В меню IDE Lazarus нажмите "Package" > "New package" для запуска диспетчера пакетов.  
  
 
[[Image:package_menu.png]]
 
[[Image:package_menu.png]]
  
* A '''Save''' file dialog will appear. Chose a folder and a file name and press save. If the IDE prompts for using lowercase filenames press 'yes'.
+
* Появится диалоговое окно "Save". Выберите папку и имя файла и нажмите "Save". Если программа IDE предложит использовать строчные имена файлов, нажмите "да".
  
* Congratulations: You have just created your first package!
+
* Поздравляем: вы только что создали свой первый пакет!
  
 
[[Image:How_to_write_lazarus_component_package_maker.png|Package Maker]]
 
[[Image:How_to_write_lazarus_component_package_maker.png|Package Maker]]
  
==Step 2: Create the unit==
+
==Шаг 2: Создание модуля==
You can create a new unit or use an existing file. Both options are described below.
+
Вы можете создать новый модуль или использовать существующий файл. Оба варианта описаны ниже.
  
===Create a new unit===
+
===Создание нового модуля===
* Use the '''Add button > New component'''.
+
* Используйте кнопку '''Add > New component'''.<br />
  
[[Image:package_new_component.png]]
+
[[Image:package_new_component.png]]<br />
  
* Choose a component like TComboBox.
+
* Выберите компонент, [например такой] как TComboBox.
* Choose ''customcontrol1.pas'' as '''Unit File Name''' and ''CustomControl1'' as '''Unit Name'''.
+
* Выберите ''customcontrol1.pas'' в качестве '''Unit File Name''' и ''CustomControl1'' в качестве '''Unit Name'''.
* You can now give to the component a icon and determine on which palette the component should appear later in the Lazarus-IDE.  
+
* Теперь вы можете задать иконку компоненту и определить, на какой палитре компонент должен появиться позже в Lazarus-IDE.  
* Click '''Create New Component'''.
+
* Нажмите '''OK'''[, чтобы создать новый компонент].<br />
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
unit CustomControl1;
 
unit CustomControl1;
  
Line 68: Line 65:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
* Install the package by clicking the '''Use -> Install''' button at the top of the package editor.
+
* Установите пакет, кликнув кнопку '''Use -> Install''' вверху редактора пакетов.<br />
 +
 
 +
[[Image:package_install.png]]<br />
  
[[Image:package_install.png]]
+
* Теперь IDE спросит вас, должна ли она быть пересобрана. Ответьте "Да".<br />
  
* Now the IDE will ask you, if the IDE should be rebuilt. Say yes.
+
[[Image:package_rebuild.png]]<br />
  
[[Image:package_rebuild.png]]
+
* Перезапустите Lazarus[, если он не сделал этого сам,] и посмотрите на свой новый компонент в палитре компонентов. Поздравляем: вы только что установили свой первый пакет с вашим первым компонентом.<br />
  
* Restart Lazarus and see your new component in the component palette. Congratulations: you have just installed your first package with your first package component.  
+
[[Image:package_installed.png]]<br />
  
[[Image:package_installed.png]]
+
{{Note| Если вы не видите свой новый компонент в палитре компонентов, скорее всего, вы используете не пересобранную версию Lazarus. Вы можете установить, где Lazarus пересобирается, используя [пункт меню] Tools -> Options -> Files -> Lazarus directory.  
  
{{Note| If you do not see your new component in the component palette, it is most likely that you are not running the re-compiled version of Lazarus. You can set where Lazarus builds to using Tools -> Options -> Files -> Lazarus directory.  
+
Вместо прямого вызова Lazarus вы также можете использовать startlazarus, который запускает недавно созданный Lazarus, например исполняемый файл Lazarus в каталоге ~ / .lazarus, если у вас нет доступа на запись в каталог, в который был установлен Lazarus.}}
  
Instead of calling Lazarus directly, you also can use startlazarus, which starts the newly created Lazarus, for example the Lazarus executable in the ~/.lazarus directory, if you don't have write access to the directory Lazarus was installed into.}}
+
----
 +
[[User:Zoltanleo|Прим.перев.]]  23:36, 1 December 2018 (CET):  В корневом каталоге Lazarus'а после пересборки обычно содержится три исполняемых файла: lazarus (текущий запускаемый файл), startlazarus (лаучер для lazarus) и lazarus.old (старая версия исполняемого файла, существующая после последней удачной пересборки среды). В примечании, вероятнее всего, речь идет о них.
 +
----
  
===Add an existing unit===
+
===Добавление существующего модуля===
If you already had a unit you can add it to the package:
+
Если у вас уже есть модуль, вы можете добавить его в пакет:
  
[[Image:package_existing_unit.png]]
+
[[Image:package_existing_unit.png]]<br />
  
* Click the '''Add''' button, go to the '''Add Files''' tab. At the Unit file name, browse to your existing file. Click '''Add files to package'''. If the package manager complains that the unit is not in the unit path, click yes to add the directory to the unit path.
+
* Нажмите кнопку '''Add''', перейдите к вкладке '''Add Files'''. В [колонке] file name модуля добавьте ваш существующий файл. Нажмите '''Add files to package'''. Если диспетчер пакетов жалуется, что модуль находится вне заданных к модулям путей, нажмите "Да", чтобы добавить каталог в пути к модулям.
* Click the '''Add''' button again, go to the '''Add Files''' tab, browse to the ''.lrs'' file and click OK (See Step 3 about creating this icon file).
+
* Нажмите кнопку '''Add''' снова, перейдите на вкладку '''Add Files''', найдите файл ''.lrs'' и нажмите "OK" (см. Шаг 3 о создании файла иконки).
* Click the '''Add''' button again, go to the '''New Requirement''' tab. In the Package name select '''LCL''' and click OK.
+
* Снова нажмите кнопку '''Add''', перейдите к вкладке '''New Requirement''' [(новая зависимость)]. В имени пакета выберите '''LCL''' и нажмите OK.
  
The end result should look like this:
+
Конечный результат должен выглядеть следующим образом:<br />
  
[[Image:How_to_write_lazarus_component_package_maker_done.png|Package Maker]]
+
[[Image:How_to_write_lazarus_component_package_maker_done.png|Package Maker]]<br />
  
* Click under the Files tree in the Package Manager. In the File Properties, make sure ''Register unit'' is checked.
+
* Щелкните по дереву файлов в диспетчере пакетов. В свойствах файла убедитесь, что установлен флажок ''Register unit''.
* Click the Options button. Select the IDE Integration tab. In Package Type, make sure Designtime and Runtime is selected.
+
* Нажмите кнопку Options. Перейдите на вкладку IDE Integration. В опции Package Type убедитесь, что выбраны [режимы] Designtime и Runtime.
* Click the Compile button to check to see that the files compile without errors.
+
* Нажмите кнопку Compile, чтобы проверить, файлы компилируются без ошибок.
* Click the Install button. Lazarus will rebuild and restart automatically.
+
* Нажмите кнопку Install. Lazarus автоматически пересоберется и перезагрузится.
  
The component is created and ready to be used:
+
Компонент создан и готов к использованию:<br />
  
[[Image:How_to_write_lazarus_component_created.png|Component Created]]
+
[[Image:How_to_write_lazarus_component_created.png|Component Created]]<br />
  
==Step 3: Create icons for the package==
+
==Шаг 3: Создание значков для пакета==
You should create 24x24 pixel size PNG files as icons. If, for Lazarus 1.8+, you want the palette icons to scale at higher screen resolutions you should also provide 36x36 and 48x48 pixel icons. The names of the larger icons require an appended '_150' and '_200' to the filename, repectively ('_150' for 150%, '_200' for 200%).
 
  
FPC is capable of using standard resource files <tt>.rc</tt> or compiled resources <tt>.res</tt> since fpc version 2.6. See [[Lazarus_Resources#FPC_resources]]
+
Вы должны создать PNG-файлы размером 24x24 пикселя в виде значков. Если для Lazarus 1.8+ вы хотите, чтобы значки палитры масштабировались при более высоких разрешениях экрана, вы также должны предоставлять значки 36x36 и 48x48 пикселей. Имена более крупных значков требуют добавления [суффиксов] "_150" и "_200" к имени файла, соответственно [увеличению разрешения] ("_150" для 150%, "_200" для 200%).
  
The <tt>.lrs</tt>: see below.
+
FPC способен использовать стандартные файлы ресурсов <tt>.rc</tt> или скомпилированные ресурсы <tt>.res</tt>, [начиная] с версии fpc 2.6. См. [[Lazarus_Resources/ru#FPC ресурсы|FPC ресурсы]].
 +
[О файлах] <tt>.lrs</tt>: см.ниже.
  
=== Using the Lazarus Image Editor===
+
=== Использование редактора изображений Lazarus===
You can use [[Lazarus_Image_Editor| Lazarus Image Editor]] to create the icons in .lrs format.
+
Вы можете использовать [[Lazarus_Image_Editor|Lazarus Image Editor]] для создания изображений в .lrs формате.
  
===Using lazres===
 
<tt>lazres</tt> is usually located in the Lazarus tools directory.
 
  
You may need to compile [[lazres]] at first use.  
+
----
Simply open the ''lazres.lpi'' in the IDE and click '''run > build''' in the menu.
+
[[User:Zoltanleo|Прим.перев.]] 17:13, 3 December 2018 (CET):  Поскольку старшие версии Лазаруса (насколько я помню, после v.1.6.х точно) позволяют задавать иконку изображения в png-формате, то удобнее всего для их создания использовать бесплатный векторный редактор [https://inkscape.org/ru InkScape], "родным" для которого является формат SVG. Среди его преимуществ:
 +
* работа со слоями
 +
* поддержка альфа-канала
 +
* предосмотр иконок в разных разрешениях (в файле настроек можно задать даже нестандартные значения)
 +
* вменяемый и оперативный саппорт (можно напрямую пообщаться с разработчиками в [https://inkscape.org/ru/community/discussion чате])
 +
* экспорт изображений в png-формат
 +
----
  
'''Create lrs file'''
+
===Использование lazres===
 +
<tt>lazres</tt> обычно находится в каталоге инструментов Lazarus.
  
To create the lrs file run:
+
Вам может понадобиться скомпилировать [[lazres]] при первом использовании. Просто откройте ''lazres.lpi'' в среде IDE и нажмите '''run > build''' в меню.
  
<code>~/lazarus/tools/lazres samplepackage.lrs TMyCom.png</code>
+
====Создание lrs-файла====
  
or, if high-resolution images are available
+
Для создания  lrs-файла запустите:
  
<code>~/lazarus/tools/lazres samplepackage.lrs TMyCom.png TMyCom_150.pgn TMyCom_200.png</code>
+
<syntaxhighlight lang=pascal>~/lazarus/tools/lazres samplepackage.lrs TMyCom.png</syntaxhighlight>
  
Where
+
или, если доступны изображения с высоким разрешением
* ''samplepackage'' is the name of your package
 
* ''TMyCom'' is the name of your component! The name of the image must match the name of your component!
 
  
You can add more than one image to the lrs file by appending the image file name at the end. Eg. ~/lazarus/tools/lazres samplepackage.lrs TMyCom.png TMyOtherCom.png ...
+
<syntaxhighlight lang=pascal>~/lazarus/tools/lazres samplepackage.lrs TMyCom.png TMyCom_150.pgn TMyCom_200.png</syntaxhighlight>
  
 +
где
 +
* ''samplepackage'' - имя вашего пакета
 +
* ''TMyCom'' - имя вашего компонента. Имя изображения должно совпадать с именем вашего компонента!
  
'''Sample'''
+
Вы можете добавить несколько изображений в файл lrs, добавив имя файла изображения в конец [команды]. Например:
 +
<syntaxhighlight lang=pascal>~/lazarus/tools/lazres samplepackage.lrs TMyCom.png TMyOtherCom.png ...</syntaxhighlight>
  
Following is a sample of the resulting ''samplepackage.lrs'' file.
 
  
<pre>LazarusResources.Add('TMyCom','PNG',[
+
'''Пример'''
 +
 
 +
Ниже приведен образец полученного файла ''samplepackage.lrs''.
 +
 
 +
<syntaxhighlight lang=pascal>LazarusResources.Add('TMyCom','PNG',[
 
   #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#2#0#0#0'o'#21#170#175
 
   #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#2#0#0#0'o'#21#170#175
 
   +#0#0#0#4'gAMA'#0#0#177#143#11#252'a'#5#0#0#0'|IDAT8O'#237#212#209#10#192' '#8
 
   +#0#0#0#4'gAMA'#0#0#177#143#11#252'a'#5#0#0#0'|IDAT8O'#237#212#209#10#192' '#8
Line 152: Line 163:
 
   +#148#168'e'#224'7f<@4'#130'u_YD'#23#213#131#134'Q]'#158#188#135#0#0#0#0'IEND'
 
   +#148#168'e'#224'7f<@4'#130'u_YD'#23#213#131#134'Q]'#158#188#135#0#0#0#0'IEND'
 
   +#174'B`'#130
 
   +#174'B`'#130
]);</pre>
+
]);</syntaxhighlight>
  
Make sure to include your resource file in your new component source by adding the following at the bottom your component's unit and including "LResources" in the uses clause
+
Обязательно включите свой файл ресурсов в исходник нового компонента, добавив нижеследующее в модуль вашего компонента и включив "LResources" в раздел uses
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
initialization
 
initialization
 
   {$I samplepackage.lrs}
 
   {$I samplepackage.lrs}
Line 162: Line 173:
  
  
'''Create res file'''
+
====Создание res-файла====
  
lazres can also create a compiled resource file, just specify a file with the .res extension, e.g.:
+
lazres также может создать скомпилированный файл ресурсов, просто укажите файл с расширением .res, например:
  
<code>~/lazarus/tools/lazres samplepackage.'''res''' TMyCom.png</code>
+
<syntaxhighlight lang=pascal>~/lazarus/tools/lazres samplepackage.res TMyCom.png</syntaxhighlight>
  
or, with high-res icons:
+
или, для иконок с высоким разрешением:
  
<code>~/lazarus/tools/lazres samplepackage.'''res''' TMyCom.png TMyCom_150.png TMyCom_200.png</code>
+
<syntaxhighlight lang=pascal>~/lazarus/tools/lazres samplepackage.res TMyCom.png TMyCom_150.png TMyCom_200.png</syntaxhighlight>
  
In this case, instead of including the lrs file in the initialization section, just include the resource file anywhere in your component source file
+
В этом случае вместо включения файла lrs в разделе инициализации просто укажите файл ресурсов в любом месте исходного файла компонента
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
   {$R samplepackage.res}
 
   {$R samplepackage.res}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
=== Использование glazres ===
 +
'''GLazRes''' это графическая версия <tt>lazres</tt>, которая может собирать файлы в файл ресурсов Lazarus (.lrs).
 +
Его можно найти в каталоге инструментов установки Lazarus.
  
 +
==Перекомпиляция пакетов==
  
=== Using glazres ===
+
Вам нужно пересобирать пакет каждый раз, когда вы вносите изменения в файл ''mycom.pas''. Чтобы пересобрать пакет, откройте файл ''samplepackage.lpk'' в диспетчере пакетов и нажмите кнопку Install.
'''GLazRes''' is the graphical version of <tt>lazres</tt> that can assemble files into a Lazarus resource file (.lrs).
 
It can be found in the tools directory of a Lazarus installation.
 
 
 
==Recompiling Packages==
 
  
You need to rebuild the package every time you make changes to the ''mycom.pas'' file. To rebuild the package, open the ''samplepackage.lpk'' file in the Package Manager and click the Install button.
+
==Удаление пакетов==
  
==Removing Packages==
+
* Чтобы удалить установленные компоненты: в меню IDE выберите Package > Configure installed packages. На следующем рисунке показан инструмент Installed Packages.
 
 
* To remove installed components: on the IDE menu, click Package > Configure installed packages. The following image shows the Installed Packages tool.
 
  
 
  [[Image:How_to_write_lazarus_component_installed_components.png|Installed Components]]
 
  [[Image:How_to_write_lazarus_component_installed_components.png|Installed Components]]
  
* Select the package you want to uninstall and click Uninstall selection.
+
* Выберите пакет, который вы хотите удалить, и нажмите Uninstall selection.
  
If something goes wrong with a package (e.g. package directory is deleted without first uninstalling it), Lazarus may not allow you to uninstall packages. To fix the problem, at the IDE menu click Tools > Build Lazarus. Lazarus will rebuild all packages and restart. You should now be able to uninstall problematic packages.
+
Если что-то пойдет не так с пакетом (например, каталог пакета удаляется без деинсталляции [пакета в первую очередь]), Lazarus может не разрешить вам удалять пакеты. Чтобы устранить проблему, в меню IDE выберите Tools > Build Lazarus. Lazarus пересоберет все пакеты и перезапустит их. Теперь вы можете удалить проблемные пакеты.
  
==Enhancing mycom.pas==
+
==Усовершенствование mycom.pas==
  
* The code in ''mycom.pas'' above gives you the basics on what you need to create a component. The following is an enhanced version with some tips on how to write procedures and events for components.
+
* Код в ''mycom.pas'' выше дает вам основы того, что вам нужно для создания компонента. Далее приведена усовершенствованная версия с некоторыми советами о том, как писать процедуры и события для компонентов.
* The ''OnChange2'' shows how to create events
+
* ''OnChange2'' показывает, как создавать события.
* The ''OnSample'' shows how to create custom events
+
* ''OnSample'' показывает, как создавать пользовательские события.
* ''MyText'' and ''MyText2'' shows different ways to write properties.
+
* ''MyText'' и ''MyText2'' показывает различные способы записи свойств.
* You can use TComboBox instead of TCustomComboBox as the base class, which publishes all properties as TComboBox.  
+
* Вы можете использовать TComboBox вместо TCustomComboBox в качестве базового класса, который [объявляет] публичными все свойства как TComboBox.  
* If TCustomComboBox is used as the base class, you'll notice a lot of properties and events will be missing in the IDE Object Inspector. To add those properties and events, just copy and paste the properties as listed below ''// properties from TComboBox''. These list of properties can be got from the TComboBox declaration in the StdCtrls unit. Omit any property which you want to handle yourself.
+
* Если TCustomComboBox используется в качестве базового класса, вы заметите, что в Инспекторе объектов IDE будет отсутствовать множество свойств и событий. Чтобы добавить эти свойства и события, просто скопируйте и вставьте свойства, перечисленные ниже [комментария] ''// properties from TComboBox''. Этот список свойств можно получить из объявления TComboBox в модуле StdCtrls. Исключите [из списка] любое свойство, которое вы хотите [определить] самостоятельно.
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
unit mycom;
 
unit mycom;
  
Line 350: Line 359:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Also you will notice that some undeclared and possibly unwanted elements exist in the IDE Object Inspector.
+
Также вы заметите, что в Инспекторе объектов IDE существуют некоторые необъявленные и, возможно, нежелательные элементы.
To remove those of them, which you do not need, you can redeclare them in the ''Published'' section as simple variables. For example:
+
Чтобы удалить те из них, которые вам не нужны, вы можете переобъявить их в разделе ''Published'' как простые переменные. Например:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang=pascal>
 
Published
 
Published
 
...  
 
...  
Line 360: Line 370:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==Using embedded (visual) components==
+
==Использование встроенных (визуальных) компонентов==
It's possible to use standard components embedded in your own components (look for example at TLabeledEdit or TButtonPanel).
+
Можно использовать стандартные компоненты, встроенные в ваши собственные компоненты (посмотрите для примера на TLabeledEdit или TButtonPanel).
  
Let's say you want to create a custom panel with a TLabel on it. With the steps described above the base package and source files can be created.
+
Предположим, вы хотите создать пользовательскую панель с TLabel на ней. С помощью описанных выше шагов  можно создать базовый пакет и исходные файлы.
Now do the following to add a TLabel to the component:
+
Теперь сделайте следующее для добавления TLabel в компонент:
* Add a private attribute for the label component (FEmbeddedLabel: TLabel;).
+
* Добавьте приватный атрибут (поле) для компонента label (<tt>FEmbeddedLabel: TLabel;</tt>).
* Add a published read-only property for the label component (property EmbeddedLabel: TLabel read FEmbeddedLabel;)
+
* Добавьте published-свойство только для чтения для компонента label (<tt>property EmbeddedLabel: TLabel read FEmbeddedLabel;</tt>)
* Create the label in the component's (overridden) constructor (FEmbeddedLabel := TLabel.Create(self); )
+
* Создайте label в конструкторе (переопределенном) компонента (<tt>FEmbeddedLabel: = TLabel.Create(self);</tt>)
* Set the parent of the component (FEmbeddedLabel.Parent := self;)
+
* Задайте родительский элемент компонента (<tt>FEmbeddedLabel.Parent: = self;</tt>)
* If the component to be embedded is not a 'subcomponent' by default (like TBoundLabel, TPanelBitBtn etc) then add the call to SetSubComponent. This is necessary for the IDE so it knows that it has to store the properties of the embedded component as well. TLabel is not a subcomponent by default so the call to the method must be added (FEmbeddedLabel.SetSubComponent(true);).
+
* Если встроенный компонент не является 'субкомпонентом' по умолчанию (например, TBoundLabel, TPanelBitBtn и т.д.), то добавьте вызов в SetSubComponent. Это необходимо для IDE, чтобы она знала, что она также должна хранить свойства встроенного компонента. По умолчанию TLabel не является субкомпонентом, поэтому необходимо добавить вызов метода (<tt>FEmbeddedLabel.SetSubComponent(true);</tt>).
  
To sum it up you would get something like this (only the essential parts are shown):
+
В итоге вы получите что-то вроде этого (показаны только основные части):
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
TEnhancedPanel = class(TCustomControl)
 
TEnhancedPanel = class(TCustomControl)
 
private
 
private
   { The new attribute for the embedded label }
+
   { Новые аттрибуты для встроенного label }
 
   FEmbeddedLabel: TLabel;
 
   FEmbeddedLabel: TLabel;
 
    
 
    
 
public
 
public
   { The constructor must be overriden so the label can be created }
+
   { Конструктор должен быть переопределен, чтобы label могла быть создана}
 
   constructor Create(AOwner: TComponent); override;
 
   constructor Create(AOwner: TComponent); override;
 
    
 
    
 
published
 
published
   { Make the label visible in the IDE }
+
   { Сделаем label видимым в IDE }
 
   property EmbeddedLabel: TLabel read FEmbeddedLabel;
 
   property EmbeddedLabel: TLabel read FEmbeddedLabel;
 
end;
 
end;
Line 394: Line 404:
 
   inherited Create(AOwner);
 
   inherited Create(AOwner);
  
   // Set default width and height
+
   // Устанавливаем дефолтовые width и height
 
   with GetControlClassDefaultSize do
 
   with GetControlClassDefaultSize do
 
     SetInitialBounds(0, 0, CX, CY);
 
     SetInitialBounds(0, 0, CX, CY);
  
   // Add the embedded label
+
   // Добавляем встроенный label
   FEmbeddedLabel := TLabel.Create(Self); // Add the embedded label
+
   FEmbeddedLabel := TLabel.Create(Self); // Добавляем встроенный label
   FEmbeddedLabel.Parent := self;        // Show the label in the panel
+
   FEmbeddedLabel.Parent := self;        // Показываем label на panel
   FEmbeddedLabel.SetSubComponent(true);  // Tell the IDE to store the modified properties
+
   FEmbeddedLabel.SetSubComponent(true);  // Говорим IDE сохранять измененные свойства
 
   FLabel.Name := 'EmbeddedLabel';         
 
   FLabel.Name := 'EmbeddedLabel';         
 
   FLabel.Caption := 'Howdy World!';
 
   FLabel.Caption := 'Howdy World!';
  
   // Make sure the embedded label can not be selected/deleted within the IDE
+
   // Убеждаемся, что встроенная label не может быть выделена/удалена средствами IDE
 
   FLabel.ControlStyle := FLabel.ControlStyle - [csNoDesignSelectable];
 
   FLabel.ControlStyle := FLabel.ControlStyle - [csNoDesignSelectable];
 
    
 
    
   // Set other properties if necessary
+
   // Задаем другие свойства, если необходимо
 
   //...
 
   //...
 
    
 
    
Line 414: Line 424:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==Using custom paint procedure==
+
==Использование пользовательской процедуры рисования==
You can always subclass a component inside your program. For example, this implements a custom Paint procedure to a TLabel:
+
Вы всегда можете переопределить компонент внутри вашей программы. Например, это реализует пользовательскую процедуру Paint для TLabel:
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
type
 
type
 
   TMyLabel = class(TLabel)
 
   TMyLabel = class(TLabel)
Line 428: Line 438:
 
procedure TMyLabel.Paint;
 
procedure TMyLabel.Paint;
 
begin
 
begin
   // your code to implement Paint, for example
+
   // ваш код для реализации Paint, например
 
   Canvas.TextOut(0,0,Caption);
 
   Canvas.TextOut(0,0,Caption);
 
end;     
 
end;     
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Now you can create a MyLabel inside your program, at run time, with that overridden Paint procedure instead of the standard one.
+
Теперь вы можете создать MyLabel внутри вашей программы во время выполнения с этой переопределенной процедурой Paint вместо стандартной.
  
For most components, and for most methods, it would be recommendable to call inherited procedure inside it:
+
Для большинства компонентов и для большинства методов было бы полезно вызвать унаследованную процедуру внутри него:
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
procedure TMyLabel.Paint;
 
procedure TMyLabel.Paint;
 
begin
 
begin
Line 443: Line 453:
 
   inherited Paint;  /////////////////////
 
   inherited Paint;  /////////////////////
  
   // your code to implement Paint, for example
+
   // ваш код для реализации Paint, например
 
   Canvas.TextOut(0,0,Caption);
 
   Canvas.TextOut(0,0,Caption);
 
end;  
 
end;  
 
</syntaxhighlight>
 
</syntaxhighlight>
  
However, inherited behavior is not desirable in this case, since the second writing action would overlap the first (inherited) one.
+
Однако унаследованное поведение нежелательно в этом случае, поскольку второе действие записи будет перекрывать первый (унаследованный).
  
==Integrating the component with the IDE==
+
==Интеграция компонента с IDE==
  
===Property editors===
+
===Редакторы свойств===
  
Property editors provide custom dialogs to edit properties in the object inspector. For most properties, like strings, string lists, images, enumerated types and others, there are already default property editors, but if a custom component has a special kind of property it may require a custom dialog to edit the property.
+
Редакторы свойств предоставляют настраиваемые диалоги для редактирования свойств в инспекторе объектов. Для большинства свойств, таких как строки, строковые списки, изображения, перечисленные типы и другие, уже есть редакторы свойств по умолчанию, но если у пользовательского компонента есть особый вид свойства, для изменения свойства может потребоваться настраиваемый диалог.
  
Each property editor is a class, which should descend from TPropertyEditor or one of its descendents and implement methods from this base class. They should be registered in the 'Register' procedure by using the function RegisterPropertyEditor from the unit PropEdits. It is a standard to name property editors with the property name followed by 'Property', for example TFieldProperty for the property editor of the TField property.
+
Каждый редактор свойств - это класс, который должен происходить из TPropertyEditor или одного из его потомков и реализовывать методы этого базового класса. Они должны быть зарегистрированы в процедуре 'Register', используя функцию RegisterPropertyEditor из модуля PropEdits. Это стандарт для имен редакторов свойств с именем свойства, за которым следует [слово] 'Property', например [имя] TFieldProperty для редактора свойств свойства TField.
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
   TPropertyEditor = class
 
   TPropertyEditor = class
 
   public
 
   public
 
     function  AllEqual: Boolean; Virtual;
 
     function  AllEqual: Boolean; Virtual;
 
     function  AutoFill: Boolean; Virtual;
 
     function  AutoFill: Boolean; Virtual;
     procedure Edit; Virtual;    // Activated by double-clicking the property value
+
     procedure Edit; Virtual;    // Активируется двойным щелчком по значению свойства
     procedure ShowValue; Virtual; // Activated by control-clicking the property value
+
     procedure ShowValue; Virtual; // Активируется щелчком по элементу управления значения свойства
 
     function  GetAttributes: TPropertyAttributes; Virtual;
 
     function  GetAttributes: TPropertyAttributes; Virtual;
 
     function  GetEditLimit: Integer; Virtual;
 
     function  GetEditLimit: Integer; Virtual;
Line 477: Line 487:
 
     function  IsDefaultValue: Boolean; Virtual;
 
     function  IsDefaultValue: Boolean; Virtual;
 
     function  IsNotDefaultValue: Boolean; Virtual;
 
     function  IsNotDefaultValue: Boolean; Virtual;
     // ... shortened
+
     // ... укорочено
 
   end;
 
   end;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
A good example for a property editor is the TFont property editor.
+
Хорошим примером для редактора свойств является редактор свойств TFont.
  
One of the most common cases for property editors is properties which are classes. Because classes have many fields and can have a variety of formats, it's not possible for Lazarus to have the object inspector edit field able to edit it, like is done for strings and numeric types.  
+
Один из наиболее распространенных случаев для редакторов свойств - это свойства, которые являются классами. Поскольку классы имеют много полей и могут иметь различные форматы, Lazarus не может иметь [универсальное] поле редактирования в инспекторе объектов, способное их редактировать, [как это сделано,] например, для строк и числовых типов.
 +
 +
Для классов соглашение состоит в том, чтобы в поле значений постоянно отображалось имя класса в круглых скобках, например "(TFont)", а кнопка "..." показывала диалог для редактирования этого класса. Это поведение, за исключением диалога, реализуется стандартным редактором свойств для классов, называемых TClassPropertyEditor, который может быть унаследован при создании редакторов свойств для классов:
  
For classes, a convention is to have the value field show permanently the name of the class in parentheses, for example "(TFont)" and the "..." button shows a dialog to edit this class. This behaviour, except for the dialog, is implemented by a standard property editor for classes called TClassPropertyEditor, which can be inherited from when writing property editors for classes:
+
<syntaxhighlight lang=pascal>
 
 
<syntaxhighlight>
 
 
TClassPropertyEditor = class(TPropertyEditor)
 
TClassPropertyEditor = class(TPropertyEditor)
 
public
 
public
Line 500: Line 510:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Going back to the TFont example, inheriting from TClassPropertyEditor already offers part of the desired behavior and then the TFontPropertyEditor class only needs to implement showing the dialog in the Edit method and set the attributes for the editor:
+
Возвращаясь к примеру TFont, наследование от TClassPropertyEditor уже предлагает часть желаемого поведения, а затем классу TFontPropertyEditor необходимо реализовать отображение диалога в методе Edit и установить атрибуты для редактора:
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
   TFontPropertyEditor = class(TClassPropertyEditor)
 
   TFontPropertyEditor = class(TClassPropertyEditor)
 
   public
 
   public
Line 529: Line 539:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Component editors===
+
===Редакторы компонентов===
  
Component editors control the behavior of right-clicking and double clicking components in the form designer.
+
Редакторы компонентов управляют поведением компонентов по щелчку правой кнопкой мыши и двойному щелчку в дизайнере форм.
  
Each component editor is a class, which should descend from TComponentEditor or one of its descendents and implement methods from this base class. They should be registered in the 'Register' procedure by using the function RegisterComponentEditor from the unit ComponentEditors. It is a standard to name component editors with the component name followed by 'Editor', for example TStringGridComponentEditor for the property editor of the TStringGrid component. Although user component editors should be based in TComponentEditor, most of its methods are actually from an ancestor, so it is necessary to also know TBaseComponentEditor:
+
Каждый редактор компонентов - это класс, который должен происходить от TComponentEditor или одного из его потомков и реализовывать методы из этого базового класса. Он должен быть зарегистрирован в процедуре 'Register', использущей функцию RegisterComponentEditor из модуля ComponentEditors. Это стандарт для именования редакторов компонентов с именем компонента, за которым следует [слово] 'Editor', например TStringGridComponentEditor для редактора свойств компонента TStringGrid. Хотя редакторы пользовательских компонентов должны быть основаны на TComponentEditor, большинство его методов на самом деле [берут начало] от предка, поэтому необходимо также знать TBaseComponentEditor:
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
   TBaseComponentEditor = class
 
   TBaseComponentEditor = class
 
   protected
 
   protected
Line 555: Line 565:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
The most important method of a component editor is Edit, which is called when the component is double clicked. When the context menu for the component is invoked the GetVerbCount and GetVerb methods are called to build the menu. If one of the verbs (which means menu items in this case) are selected, ExecuteVerb is called. There is a default component editor (TDefaultEditor) which implements Edit to search the properties of the component for the most appropriate one to be edited. It usually chooses an event, which is edited by adding it's skeleton code in the code editor and setting the cursor to be in place to add code for it.
+
Наиболее важным методом редактора компонентов является [метод] Edit, который вызывается по двойному щелчку на компоненте. Когда вызывается контекстное меню для компонента, запрашивается метод GetVerbCount и GetVerb для создания меню. Если выбран один из глаголов (что означает пункты меню в этом случае), вызывается ExecuteVerb. Существует редактор компонентов по умолчанию (TDefaultEditor), который реализует Edit для поиска свойств компонента для наиболее подходящего для редактирования. Обычно он выбирает событие, которое будет редактироваться, путем добавления скелета кода в редактор кода и установки курсора в это место.
  
Other important methods from TBaseComponentEditor are:  
+
Другими важными методами из TBaseComponentEditor являются:
* '''ExecuteVerb(Index)''' - Executes one of the extra menu items placed on the right-click popup menu;  
+
* '''ExecuteVerb(Index)''' - Выполняет один из дополнительных пунктов меню, расположенных во всплывающем меню правой кнопки мыши;
* '''GetVerb''' – To return the name of each extra popup menu item. Note that it is the responsibility of the component editor to place special menu item caption characters like & to create a keyboard accelerator and "-" to create a separator;  
+
* '''GetVerb''' – Возвращает имя каждого дополнительного пункта всплывающего меню. Обратите внимание, что редактор компонентов должен размещать специальные символы заголовка элемента, такие как &, для создания ускорителя клавиатуры и "-" для создания разделителя;  
* '''GetVerbCount''' – Returns the amount of items to be added to the popup menu. The index for the routines GetVerb and ExecuteVerb is zero based, going from 0 to GetVerbCount 1;  
+
* '''GetVerbCount''' – Возвращает количество элементов, которые будут добавлены во всплывающее меню. Индекс для подпрограмм GetVerb и ExecuteVerb равен нулю, начиная от 0 до GetVerbCount - 1;  
* '''PrepareItem''' – Called for each verb after the menu item was created. Allows the menu item to be customized such as by adding subitems, adding a checkbox or even hiding it by setting Visible to false;  
+
* '''PrepareItem''' – Вызывается для каждого глагола [(GetVerbCount и GetVerb)] после создания пункта меню. Позволяет настраивать элемент меню, например, добавляя подэлементы, добавляя флажок или даже скрывая его, устанавливая Visible в false;  
* '''Copy''' - Called when the component is being copied to the clipboard. The component data for use by Lazarus will always be added and cannot be modified. This method is instead for adding a different kind of clipboard information to paste the component in other applications, but which won't affect the Lazarus paste.
+
* '''Copy''' - Вызывается, когда компонент копируется в буфер обмена. Данные компонента при использовании Lazarus'ом всегда будут [только] добавляться и не могут быть изменены. Этот метод предназначен для  добавления различных типов из буфера обмена при вставке компонента в другие приложения, но не будет влиять на вставку в Lazarus'е.
  
A simple and interesting example is the TCheckListBox component editor which creates a dialog to edit. More convenient than implementing all methods from TBaseComponentEditor is inheriting from TComponentEditor, and this is what TCheckListBoxEditor does. This base class adds empty implementations for most methods and some default ones for others. For Edit it calls ExecuteVerb(0), so if the first item will be identical to the double-click action, which is a convention for editor, there is no need to implement Edit. This basic action for the double-click and first menu item is often a dialog, and for TCheckListBox this is also done:
+
Простым и интересным примером является редактор компонентов TCheckListBox, который создает диалоговое окно для редактирования. Более удобный, чем реализация всех методов из TBaseComponentEditor, [он]  наследуется от TComponentEditor, и это то, что делает TCheckListBoxEditor. Этот базовый класс добавляет пустые реализации для большинства методов и некоторые умолчательные для других. Для [метода] Edit он вызывает ExecuteVerb(0), поэтому, если первый пункт [popup menu] будет сопоставлен действию двойного щелчка мыши, что является условным обозначением для редактора, то нет необходимости в [ручной] реализации [кода метода] Edit. Это основное действие для двойного щелчка и первого элемента меню часто является диалогом, и для TCheckListBox это также реализуется [так]:
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
   TCheckListBoxComponentEditor = class(TComponentEditor)
 
   TCheckListBoxComponentEditor = class(TComponentEditor)
 
   protected
 
   protected
Line 582: Line 592:
 
   Dlg := TCheckGroupEditorDlg.Create(NIL);
 
   Dlg := TCheckGroupEditorDlg.Create(NIL);
 
   try
 
   try
     // .. shortened
+
     // .. укорочено
 
     Dlg.ShowModal;
 
     Dlg.ShowModal;
     // .. shortened
+
     // .. укорочено
 
   finally
 
   finally
 
     Dlg.Free;
 
     Dlg.Free;
Line 608: Line 618:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==Design-time component debugging==
+
==Отладка компонента в Design-time==
To catch design-time-errors in a (newly created) ''dbgcomponent'':
+
Чтобы отловить ошибки времени разработки во (вновь созданном) ''dbgcomponent'':
* open project <tt>C:\lazarus\ide\lazarus.lpi</tt>;
+
* откройте проект <tt>C:\lazarus\ide\lazarus.lpi</tt>;
* run project;
+
* запустите проект;
* set breakpoint in ''dbgcomponent'' in main (1st) app;
+
* установите точку останова в ''dbgcomponent'' в главном (1-ом) приложении;
* use ''dbgcomponent'' pascal code in second app;
+
* используйте  паскалевский код ''dbgcomponent'' во втором приложении;
* step through design-time component code in debug-session; do whatever is necessary;
+
* выполнить пошагово код компонента времени разработки в режиме отладки; делайте все, что необходимо;
  
==See also==
+
==См. также==
* [[Extending the IDE]]
+
* [[Extending_the_IDE/ru|Extending the IDE]]
* [[Lazarus Packages]] - A guide for creating a package under Lazarus
+
* [[Lazarus_Packages/ru|Lazarus Packages]] - A guide for creating a package under Lazarus
* [[Components and Code examples]]
+
* [[Components and Code examples/ru|Components and Code examples]]
 
* [[Lazarus Components]]
 
* [[Lazarus Components]]
 
* [[IDE Window: Add to Package]]
 
* [[IDE Window: Add to Package]]
 
* [[IDE Window: Create new package component]]
 
* [[IDE Window: Create new package component]]
 +
* [http://freepascal.ru/article/lazarus/20050530152619 Создание визуальных компонент для Lazarus] - статья Сергея Смирнова с русскоязычного ресурса
  
You can post questions regarding this page [http://forum.lazarus.freepascal.org/index.php/topic,5789.0.html here]
+
Все вопросы вы можете оставлять также [http://forum.lazarus.freepascal.org/index.php/topic,5789.0.html на этой] странице
 
 
[[Category:Lazarus]]
 
[[Category:Component Creation]]
 
[[Category:Packages]]
 
[[Category:Code]]
 
[[Category:Tutorials]]
 

Latest revision as of 07:45, 17 February 2020

Deutsch (de) English (en) español (es) magyar (hu) italiano (it) 한국어 (ko) русский (ru) 中文(中国大陆)‎ (zh_CN)


Это руководство по созданию компонентов.

Шаг 1: Создание пакета

  • В меню IDE Lazarus нажмите "Package" > "New package" для запуска диспетчера пакетов.

package menu.png

  • Появится диалоговое окно "Save". Выберите папку и имя файла и нажмите "Save". Если программа IDE предложит использовать строчные имена файлов, нажмите "да".
  • Поздравляем: вы только что создали свой первый пакет!

Package Maker

Шаг 2: Создание модуля

Вы можете создать новый модуль или использовать существующий файл. Оба варианта описаны ниже.

Создание нового модуля

  • Используйте кнопку Add > New component.

package new component.png

  • Выберите компонент, [например такой] как TComboBox.
  • Выберите customcontrol1.pas в качестве Unit File Name и CustomControl1 в качестве Unit Name.
  • Теперь вы можете задать иконку компоненту и определить, на какой палитре компонент должен появиться позже в Lazarus-IDE.
  • Нажмите OK[, чтобы создать новый компонент].
unit CustomControl1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls;

type
  TCustomControl1 = class(TComboBox)
  private
    { Private declarations }
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Standard', [TCustomControl1]);
end;

end.
  • Установите пакет, кликнув кнопку Use -> Install вверху редактора пакетов.

package install.png

  • Теперь IDE спросит вас, должна ли она быть пересобрана. Ответьте "Да".

package rebuild.png

  • Перезапустите Lazarus[, если он не сделал этого сам,] и посмотрите на свой новый компонент в палитре компонентов. Поздравляем: вы только что установили свой первый пакет с вашим первым компонентом.

package installed.png

Light bulb  Примечание: Если вы не видите свой новый компонент в палитре компонентов, скорее всего, вы используете не пересобранную версию Lazarus. Вы можете установить, где Lazarus пересобирается, используя [пункт меню] Tools -> Options -> Files -> Lazarus directory.

Вместо прямого вызова Lazarus вы также можете использовать startlazarus, который запускает недавно созданный Lazarus, например исполняемый файл Lazarus в каталоге ~ / .lazarus, если у вас нет доступа на запись в каталог, в который был установлен Lazarus.

Прим.перев. 23:36, 1 December 2018 (CET): В корневом каталоге Lazarus'а после пересборки обычно содержится три исполняемых файла: lazarus (текущий запускаемый файл), startlazarus (лаучер для lazarus) и lazarus.old (старая версия исполняемого файла, существующая после последней удачной пересборки среды). В примечании, вероятнее всего, речь идет о них.


Добавление существующего модуля

Если у вас уже есть модуль, вы можете добавить его в пакет:

package existing unit.png

  • Нажмите кнопку Add, перейдите к вкладке Add Files. В [колонке] file name модуля добавьте ваш существующий файл. Нажмите Add files to package. Если диспетчер пакетов жалуется, что модуль находится вне заданных к модулям путей, нажмите "Да", чтобы добавить каталог в пути к модулям.
  • Нажмите кнопку Add снова, перейдите на вкладку Add Files, найдите файл .lrs и нажмите "OK" (см. Шаг 3 о создании файла иконки).
  • Снова нажмите кнопку Add, перейдите к вкладке New Requirement [(новая зависимость)]. В имени пакета выберите LCL и нажмите OK.

Конечный результат должен выглядеть следующим образом:

Package Maker

  • Щелкните по дереву файлов в диспетчере пакетов. В свойствах файла убедитесь, что установлен флажок Register unit.
  • Нажмите кнопку Options. Перейдите на вкладку IDE Integration. В опции Package Type убедитесь, что выбраны [режимы] Designtime и Runtime.
  • Нажмите кнопку Compile, чтобы проверить, файлы компилируются без ошибок.
  • Нажмите кнопку Install. Lazarus автоматически пересоберется и перезагрузится.

Компонент создан и готов к использованию:

Component Created

Шаг 3: Создание значков для пакета

Вы должны создать PNG-файлы размером 24x24 пикселя в виде значков. Если для Lazarus 1.8+ вы хотите, чтобы значки палитры масштабировались при более высоких разрешениях экрана, вы также должны предоставлять значки 36x36 и 48x48 пикселей. Имена более крупных значков требуют добавления [суффиксов] "_150" и "_200" к имени файла, соответственно [увеличению разрешения] ("_150" для 150%, "_200" для 200%).

FPC способен использовать стандартные файлы ресурсов .rc или скомпилированные ресурсы .res, [начиная] с версии fpc 2.6. См. FPC ресурсы. [О файлах] .lrs: см.ниже.

Использование редактора изображений Lazarus

Вы можете использовать Lazarus Image Editor для создания изображений в .lrs формате.



Прим.перев. 17:13, 3 December 2018 (CET): Поскольку старшие версии Лазаруса (насколько я помню, после v.1.6.х точно) позволяют задавать иконку изображения в png-формате, то удобнее всего для их создания использовать бесплатный векторный редактор InkScape, "родным" для которого является формат SVG. Среди его преимуществ:

  • работа со слоями
  • поддержка альфа-канала
  • предосмотр иконок в разных разрешениях (в файле настроек можно задать даже нестандартные значения)
  • вменяемый и оперативный саппорт (можно напрямую пообщаться с разработчиками в чате)
  • экспорт изображений в png-формат

Использование lazres

lazres обычно находится в каталоге инструментов Lazarus.

Вам может понадобиться скомпилировать lazres при первом использовании. Просто откройте lazres.lpi в среде IDE и нажмите run > build в меню.

Создание lrs-файла

Для создания lrs-файла запустите:

~/lazarus/tools/lazres samplepackage.lrs TMyCom.png

или, если доступны изображения с высоким разрешением

~/lazarus/tools/lazres samplepackage.lrs TMyCom.png TMyCom_150.pgn TMyCom_200.png

где

  • samplepackage - имя вашего пакета
  • TMyCom - имя вашего компонента. Имя изображения должно совпадать с именем вашего компонента!

Вы можете добавить несколько изображений в файл lrs, добавив имя файла изображения в конец [команды]. Например:

~/lazarus/tools/lazres samplepackage.lrs TMyCom.png TMyOtherCom.png ...


Пример

Ниже приведен образец полученного файла samplepackage.lrs.

LazarusResources.Add('TMyCom','PNG',[
  #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#2#0#0#0'o'#21#170#175
  +#0#0#0#4'gAMA'#0#0#177#143#11#252'a'#5#0#0#0'|IDAT8O'#237#212#209#10#192' '#8
  +#5'P'#247#231#251's'#215#138#133#164#166'\'#220#195'`'#209'c'#157'L'#173#131
  +#153#169'd4'#168'dP'#137'r_'#235'5'#136'@Zmk'#16'd9'#144#176#232#164'1'#247
  +'I'#8#160'IL'#206'C'#179#144#12#199#140'.'#134#244#141'~'#168#247#209'S~;'#29
  +'V+'#196#201'^'#10#15#150'?'#255#18#227#206'NZ>42'#181#159#226#144#15'@'#201
  +#148#168'e'#224'7f<@4'#130'u_YD'#23#213#131#134'Q]'#158#188#135#0#0#0#0'IEND'
  +#174'B`'#130
]);

Обязательно включите свой файл ресурсов в исходник нового компонента, добавив нижеследующее в модуль вашего компонента и включив "LResources" в раздел uses

initialization
  {$I samplepackage.lrs}


Создание res-файла

lazres также может создать скомпилированный файл ресурсов, просто укажите файл с расширением .res, например:

~/lazarus/tools/lazres samplepackage.res TMyCom.png

или, для иконок с высоким разрешением:

~/lazarus/tools/lazres samplepackage.res TMyCom.png TMyCom_150.png TMyCom_200.png

В этом случае вместо включения файла lrs в разделе инициализации просто укажите файл ресурсов в любом месте исходного файла компонента

  {$R samplepackage.res}

Использование glazres

GLazRes это графическая версия lazres, которая может собирать файлы в файл ресурсов Lazarus (.lrs). Его можно найти в каталоге инструментов установки Lazarus.

Перекомпиляция пакетов

Вам нужно пересобирать пакет каждый раз, когда вы вносите изменения в файл mycom.pas. Чтобы пересобрать пакет, откройте файл samplepackage.lpk в диспетчере пакетов и нажмите кнопку Install.

Удаление пакетов

  • Чтобы удалить установленные компоненты: в меню IDE выберите Package > Configure installed packages. На следующем рисунке показан инструмент Installed Packages.
Installed Components
  • Выберите пакет, который вы хотите удалить, и нажмите Uninstall selection.

Если что-то пойдет не так с пакетом (например, каталог пакета удаляется без деинсталляции [пакета в первую очередь]), Lazarus может не разрешить вам удалять пакеты. Чтобы устранить проблему, в меню IDE выберите Tools > Build Lazarus. Lazarus пересоберет все пакеты и перезапустит их. Теперь вы можете удалить проблемные пакеты.

Усовершенствование mycom.pas

  • Код в mycom.pas выше дает вам основы того, что вам нужно для создания компонента. Далее приведена усовершенствованная версия с некоторыми советами о том, как писать процедуры и события для компонентов.
  • OnChange2 показывает, как создавать события.
  • OnSample показывает, как создавать пользовательские события.
  • MyText и MyText2 показывает различные способы записи свойств.
  • Вы можете использовать TComboBox вместо TCustomComboBox в качестве базового класса, который [объявляет] публичными все свойства как TComboBox.
  • Если TCustomComboBox используется в качестве базового класса, вы заметите, что в Инспекторе объектов IDE будет отсутствовать множество свойств и событий. Чтобы добавить эти свойства и события, просто скопируйте и вставьте свойства, перечисленные ниже [комментария] // properties from TComboBox. Этот список свойств можно получить из объявления TComboBox в модуле StdCtrls. Исключите [из списка] любое свойство, которое вы хотите [определить] самостоятельно.
unit mycom;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, StdCtrls, Forms, Dialogs,
  LCLType,LCLIntf,lresources,LCLProc;

type

  TSampleEvent = procedure(MyText: String) of Object;

  TMyCom = class (TCustomComboBox)
  private
    FMyText: String;
    FOnChange2: TNotifyEvent;
    FOnSample: TSampleEvent;
  public
    constructor Create(TheOwner: TComponent); override;
    procedure CreateWnd; override;
    procedure Change; override;
  protected
    function GetMyText2: String;
    procedure SetMyText2(MyText: String);
  published
    property MyText: String read FMyText write FMyText;
    property MyText2: String read GetMyText2 write SetMyText2;
    property OnChange2: TNotifyEvent read FOnChange2 write FOnChange2;
    property OnSample: TSampleEvent read FOnSample write FOnSample;
    
    // properties from TComboBox
    property Align;
    property Anchors;
    property ArrowKeysTraverseList;
    property AutoComplete;
    property AutoCompleteText;
    property AutoDropDown;
    property AutoSelect;
    property AutoSize;
    property BidiMode;
    property BorderSpacing;
    property CharCase;
    property Color;
    property Ctl3D;
    property Constraints;
    property DragCursor;
    property DragMode;
    property DropDownCount;
    property Enabled;
    property Font;
    property ItemHeight;
    property ItemIndex;
    property Items;
    property ItemWidth;
    property MaxLength;
    property OnChange;
    property OnChangeBounds;
    property OnClick;
    property OnCloseUp;
    property OnContextPopup;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnDrawItem;
    property OnEndDrag;
    property OnDropDown;
    property OnEditingDone;
    property OnEnter;
    property OnExit;
    property OnGetItems;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMeasureItem;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnStartDrag;
    property OnSelect;
    property OnUTF8KeyPress;
    property ParentBidiMode;
    property ParentColor;
    property ParentCtl3D;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ReadOnly;
    property ShowHint;
    property Sorted;
    property Style;
    property TabOrder;
    property TabStop;
    property Text;
    property Visible;    
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Sample',[TMyCom]);
end;

constructor TMyCom.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  Self.Style := csDropDownList;
end;

procedure TMyCom.CreateWnd;
begin
  inherited CreateWnd;
  Items.Assign(Screen.Fonts);
end;

procedure TMyCom.Change;
begin
  inherited;
  if Assigned(FOnChange2) then FOnChange2(Self);
  if Assigned(FOnSample) then FOnSample(FMyText);
end;

function TMyCom.GetMyText2: String;
begin
  Result:=FMyText;
end;

procedure TMyCom.SetMyText2(MyText: String);
begin
  FMyText:=MyText;
end;

initialization
  {$I samplepackage.lrs}

end.

Также вы заметите, что в Инспекторе объектов IDE существуют некоторые необъявленные и, возможно, нежелательные элементы. Чтобы удалить те из них, которые вам не нужны, вы можете переобъявить их в разделе Published как простые переменные. Например:

Published
... 
    property Height: Integer;
    property Width:  Integer;
...

Использование встроенных (визуальных) компонентов

Можно использовать стандартные компоненты, встроенные в ваши собственные компоненты (посмотрите для примера на TLabeledEdit или TButtonPanel).

Предположим, вы хотите создать пользовательскую панель с TLabel на ней. С помощью описанных выше шагов можно создать базовый пакет и исходные файлы. Теперь сделайте следующее для добавления TLabel в компонент:

  • Добавьте приватный атрибут (поле) для компонента label (FEmbeddedLabel: TLabel;).
  • Добавьте published-свойство только для чтения для компонента label (property EmbeddedLabel: TLabel read FEmbeddedLabel;)
  • Создайте label в конструкторе (переопределенном) компонента (FEmbeddedLabel: = TLabel.Create(self);)
  • Задайте родительский элемент компонента (FEmbeddedLabel.Parent: = self;)
  • Если встроенный компонент не является 'субкомпонентом' по умолчанию (например, TBoundLabel, TPanelBitBtn и т.д.), то добавьте вызов в SetSubComponent. Это необходимо для IDE, чтобы она знала, что она также должна хранить свойства встроенного компонента. По умолчанию TLabel не является субкомпонентом, поэтому необходимо добавить вызов метода (FEmbeddedLabel.SetSubComponent(true);).

В итоге вы получите что-то вроде этого (показаны только основные части):

TEnhancedPanel = class(TCustomControl)
private
  { Новые аттрибуты для встроенного label }
  FEmbeddedLabel: TLabel;
  
public
  { Конструктор должен быть переопределен, чтобы label могла быть создана}
  constructor Create(AOwner: TComponent); override;
  
published
  { Сделаем label видимым в IDE }
  property EmbeddedLabel: TLabel read FEmbeddedLabel;
end;

implementation

constructor TEnhancedPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  // Устанавливаем дефолтовые width и height
  with GetControlClassDefaultSize do
    SetInitialBounds(0, 0, CX, CY);

  // Добавляем встроенный label
  FEmbeddedLabel := TLabel.Create(Self); // Добавляем встроенный label
  FEmbeddedLabel.Parent := self;         // Показываем label на panel
  FEmbeddedLabel.SetSubComponent(true);  // Говорим IDE сохранять измененные свойства
  FLabel.Name := 'EmbeddedLabel';        
  FLabel.Caption := 'Howdy World!';

  // Убеждаемся, что встроенная label не может быть выделена/удалена средствами IDE
  FLabel.ControlStyle := FLabel.ControlStyle - [csNoDesignSelectable];
  
  // Задаем другие свойства, если необходимо
  //...
  
end;

Использование пользовательской процедуры рисования

Вы всегда можете переопределить компонент внутри вашей программы. Например, это реализует пользовательскую процедуру Paint для TLabel:

type
  TMyLabel = class(TLabel)
    protected
      procedure Paint; override;
  end;
{...}
implementation
{...}
procedure TMyLabel.Paint;
begin
  // ваш код для реализации Paint, например
  Canvas.TextOut(0,0,Caption);
end;

Теперь вы можете создать MyLabel внутри вашей программы во время выполнения с этой переопределенной процедурой Paint вместо стандартной.

Для большинства компонентов и для большинства методов было бы полезно вызвать унаследованную процедуру внутри него:

procedure TMyLabel.Paint;
begin

  inherited Paint;   /////////////////////

  // ваш код для реализации Paint, например
  Canvas.TextOut(0,0,Caption);
end;

Однако унаследованное поведение нежелательно в этом случае, поскольку второе действие записи будет перекрывать первый (унаследованный).

Интеграция компонента с IDE

Редакторы свойств

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

Каждый редактор свойств - это класс, который должен происходить из TPropertyEditor или одного из его потомков и реализовывать методы этого базового класса. Они должны быть зарегистрированы в процедуре 'Register', используя функцию RegisterPropertyEditor из модуля PropEdits. Это стандарт для имен редакторов свойств с именем свойства, за которым следует [слово] 'Property', например [имя] TFieldProperty для редактора свойств свойства TField.

  TPropertyEditor = class
  public
    function  AllEqual: Boolean; Virtual;
    function  AutoFill: Boolean; Virtual;
    procedure Edit; Virtual;     // Активируется двойным щелчком по значению свойства
    procedure ShowValue; Virtual; // Активируется щелчком по элементу управления значения свойства
    function  GetAttributes: TPropertyAttributes; Virtual;
    function  GetEditLimit: Integer; Virtual;
    function  GetName: ShortString; Virtual;
    procedure GetProperties(Proc: TGetPropEditProc); Virtual;
    function  GetHint(HintType: TPropEditHint; x, y: integer): String; Virtual;
    function  GetDefaultValue: AnsiString; Virtual;
    procedure GetValues(Proc: TGetStrProc); Virtual;
    procedure SetValue(const NewValue: AnsiString); Virtual;
    procedure UpdateSubProperties; Virtual;
    function  SubPropertiesNeedsUpdate: Boolean; Virtual;
    function  IsDefaultValue: Boolean; Virtual;
    function  IsNotDefaultValue: Boolean; Virtual;
    // ... укорочено
  end;

Хорошим примером для редактора свойств является редактор свойств TFont.

Один из наиболее распространенных случаев для редакторов свойств - это свойства, которые являются классами. Поскольку классы имеют много полей и могут иметь различные форматы, Lazarus не может иметь [универсальное] поле редактирования в инспекторе объектов, способное их редактировать, [как это сделано,] например, для строк и числовых типов.

Для классов соглашение состоит в том, чтобы в поле значений постоянно отображалось имя класса в круглых скобках, например "(TFont)", а кнопка "..." показывала диалог для редактирования этого класса. Это поведение, за исключением диалога, реализуется стандартным редактором свойств для классов, называемых TClassPropertyEditor, который может быть унаследован при создании редакторов свойств для классов:

TClassPropertyEditor = class(TPropertyEditor)
public
  constructor Create(Hook: TPropertyEditorHook; APropCount: Integer); Override;
  function GetAttributes: TPropertyAttributes; Override;
  procedure GetProperties(Proc: TGetPropEditProc); Override;
  function GetValue: AnsiString; Override;
  property SubPropsTypeFilter: TTypeKinds Read FSubPropsTypeFilter
                                         Write SetSubPropsTypeFilter
                                       Default tkAny;
end;

Возвращаясь к примеру TFont, наследование от TClassPropertyEditor уже предлагает часть желаемого поведения, а затем классу TFontPropertyEditor необходимо реализовать отображение диалога в методе Edit и установить атрибуты для редактора:

  TFontPropertyEditor = class(TClassPropertyEditor)
  public
    procedure Edit; Override;
    function  GetAttributes: TPropertyAttributes; Override;
  end;

procedure TFontPropertyEditor.Edit;
var 
  FontDialog: TFontDialog;
begin
  FontDialog := TFontDialog.Create(NIL);
  try
    FontDialog.Font    := TFont(GetObjectValue(TFont));
    FontDialog.Options := FontDialog.Options + [fdShowHelp, fdForceFontExist];
    if FontDialog.Execute then SetPtrValue(FontDialog.Font);
  finally
    FontDialog.Free;
  end;
end;

function TFontPropertyEditor.GetAttributes: TPropertyAttributes;
begin
  Result := [paMultiSelect, paSubProperties, paDialog, paReadOnly];
end;

Редакторы компонентов

Редакторы компонентов управляют поведением компонентов по щелчку правой кнопкой мыши и двойному щелчку в дизайнере форм.

Каждый редактор компонентов - это класс, который должен происходить от TComponentEditor или одного из его потомков и реализовывать методы из этого базового класса. Он должен быть зарегистрирован в процедуре 'Register', использущей функцию RegisterComponentEditor из модуля ComponentEditors. Это стандарт для именования редакторов компонентов с именем компонента, за которым следует [слово] 'Editor', например TStringGridComponentEditor для редактора свойств компонента TStringGrid. Хотя редакторы пользовательских компонентов должны быть основаны на TComponentEditor, большинство его методов на самом деле [берут начало] от предка, поэтому необходимо также знать TBaseComponentEditor:

  TBaseComponentEditor = class
  protected
  public
    constructor Create(AComponent: TComponent;
                       ADesigner: TComponentEditorDesigner); Virtual;
    procedure Edit; Virtual; Abstract;
    procedure ExecuteVerb(Index: Integer); Virtual; Abstract;
    function  GetVerb(Index: Integer): String; Virtual; Abstract;
    function  GetVerbCount: Integer; Virtual; Abstract;
    procedure PrepareItem(Index: Integer; const AnItem: TMenuItem); Virtual; Abstract;
    procedure Copy; Virtual; Abstract;
    function  IsInInlined: Boolean; Virtual; Abstract;
    function  GetComponent: TComponent; Virtual; Abstract;
    function  GetDesigner: TComponentEditorDesigner; Virtual; Abstract;
    function  GetHook(out Hook: TPropertyEditorHook): Boolean; Virtual; Abstract;
    procedure Modified; Virtual; Abstract;
  end;

Наиболее важным методом редактора компонентов является [метод] Edit, который вызывается по двойному щелчку на компоненте. Когда вызывается контекстное меню для компонента, запрашивается метод GetVerbCount и GetVerb для создания меню. Если выбран один из глаголов (что означает пункты меню в этом случае), вызывается ExecuteVerb. Существует редактор компонентов по умолчанию (TDefaultEditor), который реализует Edit для поиска свойств компонента для наиболее подходящего для редактирования. Обычно он выбирает событие, которое будет редактироваться, путем добавления скелета кода в редактор кода и установки курсора в это место.

Другими важными методами из TBaseComponentEditor являются:

  • ExecuteVerb(Index) - Выполняет один из дополнительных пунктов меню, расположенных во всплывающем меню правой кнопки мыши;
  • GetVerb – Возвращает имя каждого дополнительного пункта всплывающего меню. Обратите внимание, что редактор компонентов должен размещать специальные символы заголовка элемента, такие как &, для создания ускорителя клавиатуры и "-" для создания разделителя;
  • GetVerbCount – Возвращает количество элементов, которые будут добавлены во всплывающее меню. Индекс для подпрограмм GetVerb и ExecuteVerb равен нулю, начиная от 0 до GetVerbCount - 1;
  • PrepareItem – Вызывается для каждого глагола [(GetVerbCount и GetVerb)] после создания пункта меню. Позволяет настраивать элемент меню, например, добавляя подэлементы, добавляя флажок или даже скрывая его, устанавливая Visible в false;
  • Copy - Вызывается, когда компонент копируется в буфер обмена. Данные компонента при использовании Lazarus'ом всегда будут [только] добавляться и не могут быть изменены. Этот метод предназначен для добавления различных типов из буфера обмена при вставке компонента в другие приложения, но не будет влиять на вставку в Lazarus'е.

Простым и интересным примером является редактор компонентов TCheckListBox, который создает диалоговое окно для редактирования. Более удобный, чем реализация всех методов из TBaseComponentEditor, [он] наследуется от TComponentEditor, и это то, что делает TCheckListBoxEditor. Этот базовый класс добавляет пустые реализации для большинства методов и некоторые умолчательные для других. Для [метода] Edit он вызывает ExecuteVerb(0), поэтому, если первый пункт [popup menu] будет сопоставлен действию двойного щелчка мыши, что является условным обозначением для редактора, то нет необходимости в [ручной] реализации [кода метода] Edit. Это основное действие для двойного щелчка и первого элемента меню часто является диалогом, и для TCheckListBox это также реализуется [так]:

  TCheckListBoxComponentEditor = class(TComponentEditor)
  protected
    procedure DoShowEditor;
  public
    procedure ExecuteVerb(Index: Integer); override;
    function  GetVerb(Index: Integer): String; override;
    function  GetVerbCount: Integer; override;
  end;

procedure TCheckGroupComponentEditor.DoShowEditor;
var
  Dlg: TCheckGroupEditorDlg;
begin
  Dlg := TCheckGroupEditorDlg.Create(NIL);
  try
    // .. укорочено
    Dlg.ShowModal;
    // .. укорочено
  finally
    Dlg.Free;
  end;
end;

procedure TCheckGroupComponentEditor.ExecuteVerb(Index: Integer);
begin
  case Index of
    0: DoShowEditor;
  end;
end;

function TCheckGroupComponentEditor.GetVerb(Index: Integer): String;
begin
  Result := 'CheckBox Editor...';
end;

function TCheckGroupComponentEditor.GetVerbCount: Integer;
begin
  Result := 1;
end;

Отладка компонента в Design-time

Чтобы отловить ошибки времени разработки во (вновь созданном) dbgcomponent:

  • откройте проект C:\lazarus\ide\lazarus.lpi;
  • запустите проект;
  • установите точку останова в dbgcomponent в главном (1-ом) приложении;
  • используйте паскалевский код dbgcomponent во втором приложении;
  • выполнить пошагово код компонента времени разработки в режиме отладки; делайте все, что необходимо;

См. также

Все вопросы вы можете оставлять также на этой странице