Політ: книга програмера  
0. Вступ
1. Особливості політівських програм
2. Події та їх обробники
3. Елементи керування: принципи, Button, Label, Check, Radio,
InpLine, PicCtl, Header, Progress, Track, TimerCtl, Notebook,
SpinEdit, PopupBtn, Switcher, MainMenu, Splitter, Memo, ListBox

Сайт Польоту
 

Елементи керування
Загальні принципи

Пропоную почати зі створення елементів керування (ніхто не проти? :). Перше, що треба знати про політівські елементи керування - це те, що з кожним із них пов'язана змінна типу PControl (вказівник на запис типу TControl). Цей тип, як і більшість політівських типів, описаний у файлі Types.pas. Запис TControl існує для кожного екземпляра елемента керування - так само, як запис типу TProg існує для кожної працюючої в Польоті програми. Тільки записом TProg займався кернел (і передавав нашій програмі вказівник на нього). А з елементами керування нам доведеться самим робити все це - заводити змінні та передавати їх елементам керування, викликаючи їх процедури та функції.

Поки що досить теорії, перейдемо до справи. Відкриваємо наш TestApp.pas, знаходимо опис типу TTestAppData (на самому початку файла) і в нього вписуємо рядок (відразу після коментаря):
BtnTest: PControl;
Це ми завели змінну для елемента керування (це буде кнопка). Далі в обробнику OnInit знаходимо блок With TTestAppData(Data^) Do ... і вписуємо в ньому (після коментаря що тут, мовляв, елементи керування непогано створювати):
BtnTest:=Ctl.Button_Create(Me, 'Фокус', Nil, ppLeft,
  Kernel.CtlDummyProc);
Ось і все - кнопочка створена. Ми викликали функцію Button_Create модуля Ctl, передали їй необхідні параметри - підпис, іконку (Nil - без іконки), положення картинки (ppLeft - зліва від текста) та обробник натиснення кнопки (Kernel.CtlDummyProc - "порожня" процедура), ця функція повернула нам вказівник на створену кнопку, ми зберегли його у змінній BtnTest. Але якщо зараз запустити нашу програму, ніякої кнопки у вікні не буде. Зате, можливо, буде синя рамочка у випадковому місці екрана :). Справа в тому, що для повного щастя :) кнопочку треба ще й намалювати. Для цього шукаємо обробник OnPaint і в ньому відразу після коментаря про те, коли виникає ця процедура (ми тепер і самі не гірше знаємо :) пишемо:
Ctl.Button_Paint(BtnTest, 20, 20, 90);
Ось тепер можна запускати програму, у вікні з'явиться кнопочка. До речі, якщо ви вписували малювання випадкових ліній в обробнику OnIdle, краще викиньте або закоментуйте його, бо лінії ці затиратимуть нашу кнопочку, а це некрасиво. Отже, маємо кнопочку з написом "Фокус", її можна клікати мишкою. Або навіть Пробілом, бо вона - вибраний елемент керування (тому що єдиний :). Але при кліку на ній нічого не відбувається. Воно і зрозуміло, бо ми не писали ніякого обробника кліку на ній. Займемось цим; наприклад, перед обробником OnClose вставимо таку процедурку:
Procedure OnBtnTestClick(Me:PProg; Ctl:PControl);
Begin
   With TTestAppData(Me^.Data^) Do
      Button_SetCaption(BtnTest, 'Click!')
End;
І у створенні кнопки виправимо стандартний обробник Kernel.CtlDummyProc на наш OnBtnTestClick. Ось тепер кнопка реагуватиме на клік на ній. І не просто реагуватиме, а мінятиме свою властивість - підпис.

Пропоную зупинитись і ще раз уважно продивитись нашу програмку і особливо те, що стосується кнопки. Я хочу, щоб ви отримали уявлення про роботу з політівськими елементами керування взагалі. Для елемента керування заводиться змінна, елемент створюється, вказуються його властивості, процедура-обробник пов'язаної з ним події, міняються властивості. Робота з усіма іншими політівськими елементами керування відбувається абсолютно аналогічно, не складніше. Звичайно, відмінності будуть - наприклад, у списків немає підписів, як у кнопок, зате в них можна додавати елементи, сортувати їх, крім події "клік" визначені події "два кліки" та "хінт"... Але загальні принципи залишаються такими ж.



Підсумуємо формально. Спочатку нам треба для кожного елемента керування завести змінну типу PControl (незалежно від типу елемента - буде це кнопка, чи список, чи напис...) Для зрозумілості імена таких змінних я пропоную обирати так: перша частина імені вказує на тип елемента керування (кнопка - Btn, поле вводу - Inp і так далі), а друга частина - на його призначення. Наприклад, BtnTest, BtnOK, LstFiles, TrkContrast. Якщо у вікні багато написів (або міток), їх можна поназивати простіше: Lab1, Lab2, Lab3...

Другий наш крок - це створення елементів керування. Це треба робити в обробнику OnInit, у блоку With TTestAppData(Data^) Do. Всі елементи керування створюються функціями, що отримують деякі параметри елемента (залежно від його типу) та повертають вказівник на створений елемент. Виглядає це так:
CtlЗмінна:=Ctl.ТипЕлемента_Create(Me, Парам1, Парам2...);
Наприклад:
BtnTest:=Ctl.Button_Create(Me, 'Фокус', Nil, ppLeft,
  OnBtnTestClick);
PctTest:=Ctl.PicCtl_Create(Me, Me^.Icon, False, False);
Lab1:=Ctl.Label_Create(Me, 'Test', Nil, lsNormal, alRight);
InpFName:=Ctl.InpLine_Create(Me, 'polit.log', Nil);
Як неважко помітити, код цих елементів керування знаходиться в модулі Ctl.pas. Але є ще один модуль - Ctl2.pas; в ньому є кілька "додаткових" елементів керування - текстовий редактор, аналоговий годинник, список тощо. Другий модуль із елементами керування довелось завести, коли розмір коду елементів керування перевищив 64 КБ, і вони просто не влізли в один модуль (це обмеження Borland Pascal'я).

Наступне, що ми маємо зробити - це намалювати наші елементи керування. Це робиться в обробнику OnPaint. Процедури малювання різних елементів теж мають схожий вигляд:
Ctl.ТипЕлемента_Paint(CtlЗмінна, X1, Y1, X2, Y2);
Не для всіх типів елементів керування треба вказувати всі чотири координати. Наприклад, для кнопки достатньо X1, Y1, X2 (свою висоту вона і так знає), а для флажка та радіокнопки вказуються лише X1, Y1 (висота цих елементів фіксована, а ширину вони визначають самі за своїм підписом).

У багатьох елементів керування визначені події, для яких ми можемо зробити обробники і таким чином реагувати на них. Іноді ці обробники передаються елементу як параметр при створенні (для кнопок), частіше ж для цього існує спеціальна процедура:
Ctl.ТипЕлемента_SetТипОбробника(CtlЗмінна, Обробник);
Наприклад:
Ctl.Radio_SetOnChange(RadWidthFixed, OnWidthChange);
Ctl.SpinEdit_SetOnChange(SedYear, OnYearMonthChange);
Ctl2.ListBox_SetOnStrongSelect(LstFiles, OnFileStrongSelect);
Ctl2.ListBox_SetOnHint(LstFiles, OnFileListHint);
Більшість обробників має такий вигляд:
Procedure OnНазваЕлементаНазваПодії(Me:PProg;
  Control:PControl);
Але є обробники, які мають інший формат.

Ще нам може знадобитись міняти властивості елементів керування під час роботи програми. Це робиться процедурами такого вигляду:
Ctl.ТипЕлемента_SetВластивість(CtlЗмінна, НовеЗначення);
Наприклад:
Ctl.Button_SetCaption(BtnTest, 'Click!');
Ctl.InpLine_SetText(LabFName, 'gpl_ukr.txt');
Ctl.Check_SetState(ChkComments, True);
Ctl.Progress_SetValue(ProConvert, 50);
Ctl.Notebook_SetActivePage(NbkPages, 1);
За умовчанням при зміні властивостей елементи керування відразу перемальовуються, і зміни відразу ж стають "видимими". Але якщо є бажання, цим можна керувати вручну.

Дуже схожим чином ми можемо отримувати (читати) властивості елементів:
Ctl.ТипЕлемента_GetВластивість(CtlЗмінна)
Наприклад:
FileName:=Ctl.InpLine_GetText(InpFName);
N:=Ctl.Track_GetPos(TrkValue);
If Ctl.Check_GetState(ChkComments) Then ...
Думаю, загальне уявлення про політівські елементи керування ви отримали. У наступному розділі ми конкретно обговоримо роботу з кожним із елементів керування. А поки що, студенти, можете піти погуляти ;).