Form Tutorial
The form (class TForm) represents a window or dialog box that is the user interface of an application. It is the container on which all other components (e.g. buttons, labels, edit fields, images, etc.) are inserted .
The First GUI Application
Upon successfully installing Lazarus and starting a new Application Project, an empty form is created. Otherwise you can create a new GUI application under Main menu -> Project -> New Project -> Application OK.
Now you have created a new, fully functional project with a form:
To run the newly created project, you can simply press the F9 key or click with the mouse on the main menu icon
(or Main menu: Run -> Run). The project will be compiled and executed.
Nothing really exciting happens. The form (Form1) changes slightly in appearance and the points from the raster grid (help for positioning of individual components) disappear (as long as the grid points are visible, you also know that it is still in design mode):
->
Next, you can place a TButton onto the form. This will be used later to allow the opening of a second form:
Select the TButton from the Standard tab on the Component Palette.
and click on the form: There is now a button placed on Form1 with the name and caption «Button1».
In order for this button to do something, you have to announce that you intend to do something when you click it. This can be regarded as a simple event. For this you need an event handler that is called after the click. The event handler for a mouse click can be quite easily reached by double-clicking on Button1 (or in the Object Inspector, select Button1 -> Events tab -> OnClick, then click on the [. ] button). This creates a procedure TForm1.Button1Click in the code editor, which is always called (at runtime, not in design time) when Button1 is clicked:
To make the application do something after clicking on Button1, add some code between the Begin and End of the procedure TForm1.Button1Click like this:
Now run the form by pressing F9 , and notice that when the button is clicked the form caption and the button caption both change.
You can now experiment a little bit and learn how to use the standard components. To get started, I would recommend you to try samples of the following components:
There is additional helpful information in the Lazarus Tutorial.
The Use of a Second Form
The tutorial shows how to use multiple forms in a project. In this example, only two forms, Form1 (main form) and Form2, are created, but the process is identical for additional forms.
There is a main form with a button, which when clicked opens the new form. The new form also receives a button which when clicked closes the new form and returns you to the main form.
If you have worked through the first tutorial The first GUI app, you will need to delete the code between the begin and end of procedure TForm1.Button1Click. Otherwise you will need to create a new project (application), drop a button on the form, and create the OnClick event handler for this Button1.
Click the new button to enter a caption (visible text on the button). To do this, select the button (just click it once) and in the Object Inspector click Properties -> Caption, and enter the text «Open Form2».
In the Main menu click File -> New Form, to add a second form (Form2) to the project. Place a button (Button1) on Form2 and create the OnClick event handler for it. Change the caption of this button to «Close».
Now the project has two forms, each of which can be selected and displayed with Main menu Project -> Forms (or key combination ⇧ Shift + F12 ). Alternatively, you can select the tab for a Unit in the Source Editor, then use F12 to switch between the code editor and form designer for the form of the associated Unit.
In the source code editor, go to the Form1 associated Unit (Unit1) and add «Unit2» to the Uses clause:
Now you can call Unit2 (and thus Form2) from Unit1.
Next, edit the OnClick event of the button belonging to Form1:
Now you can start the project (
or F9 ) and open Form2 by clicking the button on Form1.
Difference between Show and ShowModal
Both methods Show and ShowModal make a form visible. To see the difference between Show and ShowModal:
- Extend the previous example The use of a second form by adding a second TButton to Form1.
- Select Button1 and change the properties Name to btnShow and Caption to Show.
- Select Button2 and change the properties Name to btnShowModal and Caption to ShowModal.
- Create (or modify) the OnClick event handler of the two buttons as follows:
- Start and watch the difference!
This procedure makes a form visible and continues to execute the code of the calling control (Form1). In our example, the message (ShowMessage) appears almost simultaneously with Form2. You can also continue to use the calling form Form1. For example, it is possible to move it, or click the Show button again (but clicking ShowModal will cause an error).
Instead of using <myForm>.Show; , it is also possible to use <myForm>.Visible:=True; . The method Show does the following:
The only difference between <myForm>.Show; , and <myForm>.Visible:=True; is that the form displayed using Show will be on top of all other forms currently displayed.
ShowModal halts the processing of code in the calling control (Form1) until the newly opened form (Form2) has been closed. In the example, the ShowMessage line immediately following ShowModal is executed only after Form2 is closed. The calling form is frozen: You can neither move Form1 nor click any of its buttons.
ShowModal is a function that returns an integer result, see TModalResult. The returned value allows branching based on how the form was closed.
Two Forms That Can Call Each Other
It is generally good program design to avoid calling the main form from a second form. It is better to return to the main form by closing the second form (as in the previous example) and letting focus revert to the main form. It is, however, possible to call the main from from a sub-form, as this example will show.
In order for Form1 to call Form2, Unit1 must have Unit2 in its Uses clause. Conversely, for Form2 to call Form1, Unit2 must have Unit1 in its Uses clause. This leads to a potential Circular Unit Reference compiler error, with each Unit referring to the other. This example also shows how to avoid the Circular Unit Reference error.
To set up this example, either modify the forms from the previous example (The Use of a Second Form), or create a new project with two forms, each having a single button. Set the caption of Form1.Button1 to «Open Form2», and set the caption of Form2.Button1 to «Open Form1».
If you are modifying the previous example, remove «Unit2» from the Uses clause in Unit1.
Add a Uses clause to the Implementation section of each Unit. Add Unit2 to the Unit1 clause, and add Unit1 to the Unit2 clause, as below:
Now change the code located behind the OnClick event of the button event handler:
Passing Variables to Other Forms
In accordance with the above example The Use of a Second Form, it is possible to declare a global variable in the interface part of Unit2. This would allow access in both Unit1 and Unit2 to one and the same variable (This is because by putting Unit2 in the Uses clause of Unit1, all variables declared in the interface part of Unit2 are also available in Unit1). This practice should be limited to a minimum, as it quickly becomes difficult to remember which individual variables are in scope, potentially increasing errors. It is better to use local variables, define a Property in a Class or, alternatively, as a variable in a class.
In the next project, a second form is opened by clicking on the button. In this case, in the unit of the main form is counted how often the second shape has been shown. In this second form you can ask to see by clicking on the button, how often it has been opened:
- a new project with two forms, each a button on it and their OnClick events to evaluate.
- now, in the public part of the Class TForm2 (Unit2) a variable (in this case a constant, which we defined as variable abuse) of type integer with the name Count create:
- now even customize the Button event handler accordingly:
In this way you can in Unit1 access all public variables/properties/functions/procedures (general methods) of Unit2.
Other Form-Related Subjects
Use Another Form as the Main Form
If you determine after a while that you want to have displayed rather a different form or new form for the view at startup, you can under the main menu Project -> Project Options -> Forms:
Alternatively, you can display, in Mainmenu -> Project -> Show .lpr file, that Project.lpr (Pascal code of the main program) and create the first form to be displayed as the first:
Save properties of the shape at end of program
Generate the form dynamically
Create a Lazarus designed form dynamically
You do not have to create all the forms that may be called during the term of an application at startup. Some developers generally keep none of it and delete the code automatically created when you insert a new form in a project from the Projekt.lpr out immediately. If you want to write a library that contains a couple of GUIs, you can not get around the dynamic creation of forms.
- new application with two forms, Form1 a button (add «Unit2» in the uses clause of unit1)
- open the Projekt.lpr (Project -> lpr file.)
- delete the line «Application.CreateForm(TForm2, Form2);»
- in the OnClick event of Button1, Form1 add following code:
- now simply start
Creating a new form dynamically
The following example will demonstrate how new forms can be generated in code, without using the Form Designer,.
In this example clicking a button should open another form that itself contains a button. Clicking this second button makes a message appear warning that the form will close; then the form is closed.
Создание форм в режиме дизайна
После выбора для создания форм режима дизайнаоткроется окно (рис.9), на котором, пользуясь панелью инструментовЭлементы управления, следует расположить элементы формы.
Рисунок 9. Окно для создания форм в режиме дизайна
Создание простой формы
В открывшемся окне следует произвольным образом расположить элементы управления (элементы формы), например, поля (текстовое, числовое, дата, время и т. д.) и указать названия этих полей. На рисунке 10 показан пример создания формы для таблицы Работники. Кнопка, позволяющая создавать текстовые поля также показана на рисунке 10. Свойства полей (элементов формы) можно указать путем выбора из контекстного меню командыЭлементы управления. В открывшемся окнеСвойстваследует включить закладку Общие. Здесь указывается цвет фона, шрифт, обрамление поля (без обрамления или фрейма, плоское, трехмерное) и прочее (рис. 11).
Рисунок 10. Создание форм в режиме дизайна
Рисунок 11. Окно Свойства. Закладка Общие
Для того, чтобы заменить текстовое поля на любое другое, необходимо поле, надлежащее замене, выделить, вызвать относительно него контекстное меню и выбрать команду Заменить на(рис. 12).
Рисунок 12. Замена поля
Далее следует установить связь между созданной формой и таблицей (запросом), данные которой (которого) будет пополнять или отображать создаваемая форма. Для этого на панели инструментов Дизайн формы следует нажать кнопкуНавигатор форм (рис. 10). Открытое окноНавигатор формпоказано на рисунке 13.
Рисунок 13. Навигатор форм
В окне Навигатор формотносительно самой формы (Standard) следует вызвать контекстное меню и выбрать командуСвойства. В появившемся окнеСвойства формыследует выбрать закладкуДанныеи указатьТип содержимого источника(таблицу или запрос, данные которых будет отображать или пополнять форма) иСодержимое(имя таблицы или запроса). В данном случаеТип содержимого источника — таблица,содержимое— Работники (рис. 14).
Рисунок 14. Окно Свойства формы. Закладка Данные
Теперь каждому элементу формы (в данным случаям полям) следует указать поле данных, т. е. то поле таблицы или запроса, которые должно будет пополниться или отобразиться при запуске создаваемой формы. Для этого в окне Свойства(вызываемом через командуЭлементы управленияконтекстного меню) следует выбрать закладкуДанныеи выбрать из списка поле данных (рис. 15).
Рисунок 15. Окно Свойства. Закладка Данные 7
Созданная таким образом форма также как и созданная в реждиме мастера форма позволяет в зависимости от указанных свойств, вводить или отображать данные таблиц (запросов).
Создание субформы
Для создания субформы в режиме дизайна следует использовать Навигатор форм.
Например, создадим субформу, состоящую из трех таблиц: Работники, Стеллажи, Документы.
Вначале создается простая форма Работники.Затем в окнеНавигатор формпри помощи контекстного меню добавляется еще одна форма (рис. 16).
Рисунок 16. Добавление формы
После добавления формы следует обычным способом наносить элементы управления (поля) и их надписи. Все нанесенные элементы управления отображаются в окне Навигатора форм (рис. 17). Количество добавления форм неограниченно.
Рисунок 17. Навигатор форм, содержащий три формы
Далее следует в окне Свойства формы (для каждой из трех форм)указатьТип содержимого источника и Содержимое. В данном случае для всех трех формТип содержимого источникаодин и тот же — таблица, аСодержимое— соответственноРаботники, Стеллажи, Документы.
Теперь для каждого элемента формы (поля) в окне Свойствас включенной закладкойДанныеследует указатьПоле данных.
Между тремя формами, входящими в состав субформы, должна быть организована связь, иначе записи, сделанные в указанных полях не будут друг другу соответствовать. Для создания связи между формами необходимоотносительно подчиненной формывызвать окноСвойства форми включить закладкуДанные. В появившемся окне следует найти записьСвязь с главным полем и нажать на кнопку вызова окна связей, показанную на рисунке 18.
Рисунок 18. Установление связей между формами
После этого откроется окно, где по принципу установления связей между таблицами следует установить связь между формами (рис. 19).
Рисунок 19. Связь полей форм.
После установления связей окно Свойства формбудут выглядеть следующим образом (рис. 20).
Рисунок 20. Окно Свойства формпосле установления связей
Такую же процедуру по установлению связей следует проделать и между остальными формами 8 .
В создаваемую форму можно вставлять рисунки или картинки из галереи. Соответствующие кнопки представлены на рисунке 21.
Рисунок 21. Оформление формы
Работа с формами Lazarus
Эта статья врядли будет интересна тем, кто раньше программировал в Delphi. Она в большей степени рассчитана на программистов VB, MS Access и других средств быстрой разработки. В каждой системе существуют свои правила и подходы, касающиеся программного открытия экранных форм, а также передачи и возврата пареметров. Вот я и хочу рассказать о том, как это сделано в Lazarus. При этом я предполагаю, что читатель достаточно хорошо понимает принципы ООП и уже знаком с синтаксисом языка Free Pascal.
Открытие форм в модальном режиме
Наиболее очевидным применением программного открытия дополнительной формы является выбор или поиск какого-либо значения в справочнике с последующим возвратом, например, кода найденного элемента в основную форму. Такую форму надо открывать модально, так как нет смысла продолжать выполнение основной программы, пока не сделан выбор и форма не закрыта. Попробуем это реализовать.
В качестве примера создадим новый проект и на главную форму поместим пару полей ввода и кнопок:

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

В качестве программного интерфейса для передачи параметра будем использовать свойство TestValue, которое определим в секции public класса формы. Также определим и реализуем более чем очевидные методы для установки и считывание значения свойства, а также обработчик события нажатия на кнопку, в котором свойству формы ModalResult присваивается значение mrOK, что и приводит к закрытию (но не уничтожению!) формы.
Однако, самый большой интерес представляет функция RunTestForm. Как можно заметить, она определена вне класса формы, хотя и в том же модуле. Это может показаться странным программистам VB, где модуль класса полностью отождествляется с самим классом. Как и в Delphi, в Lazarus это не так. Хотя в одном модуле можно определить только одну форму (иначе визуальный дизайнер форм не сможет работать), другие элементы приложения не обязательно реализовывать отдельно. В нашем случае функция RunTestForm содержит код, необходимый для создания формы, передачи ей начального значения поля ввода и возврата отредактированного значения. Очевидно, что RunTestForm по смыслу связана с классом формы, поэтому будет разумно (хотя и вовсе не обязательно) расположить её в модуле формы.
Теперь посмотрим, как использовать всё это в основной форме. Добавим в обработчики событий нажатия на кнопки вызовы функции RunTestForm, в результате чего раздел реализации модуля главной формы приобретёт такой вид:
Вот и всё. Только не забудьте в свойствах проекта удалить дополнитетьную форму из списка автоматически создающихся форм. Теперь можно потестировать, то, что у нас получилось. Запустите программу и понажимайте кнопки на главной форме. Обратите внимание, что пока дополнительная форма присутствует на экране, Вы не можете перевести фокус на какую-либо другую форму, как и положено для модального режима. И наверняка Вы подумаете, что такое поведение не всегда является подходящим. Вот это и обсудим далее.
Открытие форм в немодальном режиме
Итак, для начала определимся, что предназначение, поведение немодальной формы и принципы работы с ней совершенно другие. Прежде всего, немодальные формы не приспособлены для возврата значений, так как после их открытия программа не останавливается в ожидании закрытия формы, а продолжает выполняться. Из-за этого, если не предпринять специальных мер, указатель на открываемую форму будет утерян после завершения работы кода, который её создаёт (в нашем случае — это функция RunTestForm). Так ли это ужасно? В большинстве случаев — нет. Помните, что при создании экземпляра формы в конструктор передавался параметр Application? Так вот: Application — это объект, который представляет всё наше приложение. При таком создании формы он будет помнить о её присутствии, а мы сможем этим воспользоваться. Создадим в главной форме список, который будем заполнять именами форм, открытых в приложении. Основная форма при этом несколько изменится и будет выглядеть примерно так:

Обратите внимание, что мы задекларировали новый метод FillWindowsList, который как раз и выполняет заполнение списка форм приложения. Его реализация не слишком сложна:
Здесь есть некоторый интересный момент. Дело в том, что объект Application содержит единый список всех компонент, которыми владеет, поэтому приходится проверять, что очередной компонент является именно TForm.
Однако, что толку просто выводить список форм. Нужно сделать так, чтобы можно было переключиться на любую из них. В реальном приложении это, конечно, лучше сделать с помощью меню, но код получится несколько более громоздким, поэтому в нашем простом примере во-первых будем использовать список, а во-вторых опустим необходимые в реальном приложении проверки.
Ниже представлен весь код секции реализации модуля основной формы. Обратите внимание, что вызывая метод RunTestForm мы уже не ждём возвращаемого значения, но зато вызываем процедуру заполнения списка окон приложения.
Теперь создадим дополнительную форму, которую будем открывать из главной формы в немодальном режиме. Внешне она ничем не будет отличаться от рассмотренной в предыдущей главе модальной формы, а вот код несколько изменится. Обратите внимание, что свойство TestValue теперь только для записи, а метод RunTestForm стал процедурой вместо функции.
Появилась и новая глобальная переменная — счётчик форм Form2Count. Она понадобится нам, когда создаваемому экземпляру формы мы будем присваивать имя. Все объекты приложения должны иметь уникальные имена, однако LCL об этом никак не заботится, поэтому придётся действовать самостоятельно. Код, связанный с переменной Form2Count достаточно тривиален, поэтому останавливаться на нём не будем.
Реализация тоже довольно сильно изменилась. Показ формы теперь производится вызовом метода Show, а не ShowModal, поэтому выполнение программы не передаётся в создаваемую форму до её закрытия, а продолжается. О закрытии и освобождении ресурсов теперь должна заботиться сама форма. Для этого в процедуре обработки события закрытия формы мы присвоим переменной CloseAction значение caFree. Нажатие на кнопку теперь вызывает не установку значения ModalResult, а явное обращение к методу Close.
Если Вы не просто читали эту статью, а создавали попутно описанную тестовую программу, самое время её запустить. Только снова не забудьте убрать дополнительную форму из списка автоматически создающихся при старте приложения.
Введение в FormsABC
FormsABC — учебный модуль PascalABC.NET для работы с простейшими оконными приложениями без дизайнера форм. Основан на устаревшей технологии Windows Forms.
- Данный модуль является устаревшим (может быть в будущем исключен из среды) и специфическим для PascalABC.NET и не поддерживается другими диалектами Pascal и остальными языками. Современный аналог — Controls.
- Программы с использованием FormsABC рекомендуется запускать без связи с оболочкой.
Содержание
Основные классы [ править ]
FormsABC содержит следующие классы элементов управления формы:
- Button (кнопка) [аналог в Windows Forms]
- CheckBox (флажок) [аналог в Windows Forms]
- RadioButton (радио-кнопка) [аналог в Windows Forms]
- IntegerField (поле ввода целых значений) [аналог в Windows Forms]
- RealField (поле ввода вещественных значений) [аналог в Windows Forms]
- Field (поле ввода строк) [аналог в Windows Forms]
- TextBox (многострочное текстовое поле) [аналог в Windows Forms]
- TrackBar (ползунок) [аналог в Windows Forms]
- TextLabel (метка) [аналог в Windows Forms]
- ListBox (список) [аналог в Windows Forms]
- ComboBox (разворачивающийся список) [аналог в Windows Forms]
- MainMenu (главное меню) [аналог в Windows Forms]
Button [ править ]
Button (наследуется от Object) — класс кнопки. Для ее создания пишите:
- — текст на кнопке
CheckBox [ править ]
CheckBox (наследуется от Object) — класс флажка. Для его создания пишите:
- — текст, относящийся к флажку
- true — установлен
- false — не установлен
RadioButton [ править ]
RadioButton (наследуется от Object) — класс радио-кнопки. Для её создания пишите:
- — текст, относящийся к радио-кнопке
- true — выбрана
- false — не выбрана
IntegerField [ править ]
IntegerField (наследуется от Field) — класс однострочного поля ввода для целых чисел. Для его создания пишите:
- — текст, относящийся к полю
- — ширина поля
RealField [ править ]
RealField (наследуется от Field) — класс однострочного поля ввода для вещественных чисел. Для его создания пишите:
- — текст, относящийся к полю
- — ширина поля
Field [ править ]
Field (наследуется от Object) — класс однострочного поля ввода для строк. Для его создания пишите:
- — текст, относящийся к полю
- — ширина поля
TextBox [ править ]
TextBox (наследуется от BaseDockControl) — класс многострочного поля ввода для строк. Для его создания пишите:
| Свойство | Значение |
|---|---|
| Width | Ширина поля. |
| Height | Высота поля. |
| Text | Строка, которая содержится в поле ввода. |
| Метод | Описание |
|---|---|
| Undo() | Отменяет последнее изменение. |
| Redo() | Отменяет отмену последнего изменения. |
| Cut() | Вырезает выделенное. |
| Copy() | Копирует выделенное. |
| Paste() | Вставляет текст из буфера обмена в местоположение курсора. |
| AddLine( |
Добавляет текст новой строкой. |
TrackBar [ править ]
TrackBar (наследуется от Object) — класс ползунка. Для его создания пишите:
| Свойство | Значение |
|---|---|
| Frequency | Расстояние через которое расставляются деления на ползунке (в пикселях). |
| Minimum | Минимальное значение ползунка. |
| Maximum | Максимальное значение ползунка. |
| Value | Значение ползунка. |
| Событие | Описание |
|---|---|
| ValueChanged | Хранит ссылку на процедуру, которая выполняется при смене значения ползунка. Для установки его значения используйте +=. |
TextLabel [ править ]
TextLabel (наследуется от Object) — класс метки. Для её создания пишите:
- — текст метки
ListBox [ править ]
ListBox (наследуется от Object) — класс списка. Для его создания пишите:
| Свойство | Значение |
|---|---|
| Count | Количество элементов в списке. |
| SelectedIndex | Индекс выбранного элемента списка. |
| SelectedItem | Выбранный элемент списка. |
| Items.Item[k] | K-ый элемент списка. |
| Событие | Описание |
|---|---|
| Click | Хранит ссылку на процедуру, которая выполнится при щелчке по списку. Для установки его значения используйте +=. |
| SelectedIndexChanged | Хранит ссылку на процедуру, которая выполнится при смене выбранного элемента списка. Для установки его значения используйте +=. |
| Метод | Описание |
|---|---|
| Items.Add(t) | Добавляет в список элемент с текстом t на нем. |
| Items.Clear() | Удаляет все элементы списка. |
ComboBox [ править ]
ComboBox (наследуется от Object) — класс списка. Для его создания пишите:
| Свойство | Значение |
|---|---|
| Width | Ширина списка. |
| Count | Количество элементов в списке. |
| SelectedIndex | Индекс выбранного элемента списка. |
| SelectedItem | Выбранный элемент списка. |
| Items.Item[k] | K-ый элемент списка. |
| Событие | Описание |
|---|---|
| Click | Хранит ссылку на процедуру, которая выполнится при щелчке по списку. Для установки его значения используйте +=. |
| SelectedIndexChanged | Хранит ссылку на процедуру, которая выполнится при смене выбранного элемента списка. Для установки его значения используйте +=. |
| Метод | Описание |
|---|---|
| Items.Add(t) | Добавляет в список элемент с текстом t на нем. |
| Items.Clear() | Удаляет все элементы списка. |
MainMenu [ править ]
MainMenu (наследуется от Object) — класс главного меню. Для его создания пишите:
| Свойство | Значение |
|---|---|
| Item | Пункт меню. |
| Метод | Описание |
|---|---|
| Add( |
Добавляет перечисленные через запятую пункты меню. |
Размещение элементов управления формы [ править ]
Изначально элементы управления формы размещаются по порядку — каждый следующий позиционируется справа от предыдущего.
| Функция | Значение |
|---|---|
| LineBreak | Переходит на новую строку. |
| EmptyLine | Пропускает n пикселей по вертикали. Следующий элемент управления будет располагаться через n пикселей по вертикали от предыдущего. |
| EmptySpace | Пропускает n пикселей по горизонтали. Следующий элемент управления будет располагаться через n пикселей по горизонтали от предыдущего. |
Свойства формы [ править ]
Настраивать главную форму можно через глобальную переменную mainForm.