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

Сайт Польоту
 

Особливості політівських програм

Ну, давайте починати. У цьому розділі я пропоную зробити маленьку політівську програмку (це зовсім нескладно), трохи погратися з нею, а потім уважно вивчити і зрозуміти її текст.



Як зробити власну програму під Політ?

Не так уже і важко.

У Польоті запускаємо програмку "Майстер додатків" і відразу клікаємо кнопку "Зробити заготовку". Він покаже хінт - мовляв, готово, зробив. І це дійсно все - найпростіша політівська програмка (так би мовити, заготовка) готова! Щоб побачити її в роботі, виходимо з Польоту, у Паскалі відкриваємо POLIT.PAS, додаємо у секцію Uses назву нашої програмки (TestApp), компілюємо і запускаємо Політ. Тепер у головному меню з'явилася наша "Тестова програмка", звідси її можна запустити. Це буде порожнє вікно із заголовком, іконкою, кнопками згортання, розгортання та закриття та resizable рамочкою.

Повторимо експеримент. Але цього разу перед тим, як клікати "Зробити заготовку", уважніше оглянемо вікно Майстра додатків. Отже, що ми там бачимо?
  • Ім'я файла, Заголовок вікна - no comments.
  • Файл іконки - ясно; можете намалювати власну іконку та прописати її тут.
  • Мін. розміри вікна - ясно.
  • Вигляд вікна - це вигляд рамки навколо вікна. Може бути BlueWin (звичайне вікно, яке може міняти розмір), BlueDlg (діалогове вікно, без можливості зміни розміру), GrayBox (прямокутник з 3D-рамкою), UpperPan/LowerPan (прямокутник з полоскою, чорною внизу або білою вгорі відповідно), EmptyWin (взагалі порожнє вікно). Хінт: якщо в ході експериментів ви створите вікно, яке буде не так просто закрити, скористайтеся для цього програмкою Менеджер задач.
  • Додаткові модулі - поки не чіпаємо.
  • Флажок Ставити коментарі - ясно.
Ще у вікні є сторінка Обробники, але там теж поки краще нічого не чіпати.

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

Тепер давайте подивимось на текст отриманої програми. Беремо Борланд Паскаль та відкриваємо в ньому нашу програму, TESTAPP.PAS. З'являється віконце з текстом типу:
{$F+}
Unit
   TestApp; { Polit Halcyon TestApp application }
...
Якщо уважно придивитись, можна познаходити в цьому тексті всі параметри, які ми вводили у Майстрі програм (а також ті, які ми залишили за замовчанням :). Наприклад, введене ім'я файла - це тут назва модуля. А в самому кінці програми, у рядку Kernel.RegBuiltIn можна знайти введений заголовок вікна та файл іконки. От тільки ім'я файла навіщось записане двічі. Справа тут ось у чому: другий параметр процедури RegBuiltIn - це назва програми, яка буде показана у головному меню. За умовчанням це ім'я її файла. Отже, можна сміливо заміняти його на "Internet Explorer" або "Пасьянс Косынка" :).

Насправді ми можемо досить серйозно міняти вигляд та поведінку нашої програмки, просто отак міняючи параметри різних процедур та функцій. Скажімо, десь на один PgUp вище рядка Kernel.RegBuiltIn є рядок Kernel.InitWindow. Тут можна помітити введену раніше назву оформлення рамки вікна. І не тільки :). Третій параметр процедури - це множина кнопок керування вікном. Це може бути будь-яка комбінація таких кнопок:
  • wbMin (згорнути вікно)
  • wbMax (максимізувати)
  • wbClose (закрити)
  • wbHelp (поки нічого не робить)
  • wbSlide (закрити панель або листок, поки краще не юзайте)
  • wbDetach (поки нічого не робить)
А якщо між Kernel.InitWindow та Kernel.DrawWindow вписати
WinBG:=bgManual;
то ми отримаємо прозоре вікно :).

До речі, якщо взагалі викинути обидва рядки InitWindow та DrawWindow, то у нас вийде програма без вікна. Але зараз краще не робіть цього :).

Думаю, ви уже звертали увагу на те, що наша програмка зовсім не схожа на ДОСівські програми та трохи не схожа на програми Delphi. Зараз я почну вам розповідати, чим саме відрізняються політівські програми і чому.

Якщо ви раніше програмували під DOS, вас може здивувати заголовок програми - Unit TestApp. Так, політівські програми зараз оформлюються у вигляді модулів. Це має свої плюси і мінуси, і колись скоріш за все зміниться; але поки що це так, і нам доведеться жити з цим :).

Їдем далі. Далі іде досить довгий рядок Uses, хоча і не такий довгий, як буває у Delphi :). Тут перелічені стандартні Політівські модулі, якими користуватиметься наша програма. Про призначення кожного з них я розповідав у кінці вступу.



Крім цього, у політівських програм є ще дві великих особливості. Перша - на відміну від ДОСівських програм, власне код програми не розташований в операторній частині (там має бути лише виклик Kernel.RegBuiltIn), а складається з кількох процедур із чітко визначеним форматом заголовку та призначенням (OnPaint, OnClose, OnInit etc). Процедури ці називаються обробниками подій. Назвали їх так через те, що кожна з них викликається ядром у момент виникнення певної події. OnInit викликається при запуску нашої програми, OnPaint - коли треба промалювати її вікно, OnClose - при виході з програми (закритті). На щастя, Майстер програм зробив для нас заготовки всіх потрібних процедур-обробників і навіть поставив короткі коментарі про їх призначення. Нам лишається лише повписувати туди код нашої програми.

Якщо ви уже програмували на Delphi, то ви знайомі з принципом подій та обробників. А для тих, хто прийшов до нас із DOS :) і програмував тільки на Паскалі, поговоримо про це ще трохи. Отже, у Польоті (як і у Windows) програма виконується не від початку операторної частини до кінця, як у DOS - тут все трохи складніше. Операторна частина призначена лише для реєстрації програми, щоб Політ зміг при потребі знайти та запустити її. Виконання політівської програми починається з процедури-обробника OnInit. У цій процедурі програма має виконати деякі підготовчі дії - створити собі вікно, отримати пам'ять під змінні (все це Майстер програм прописує сам). Після цього, якщо потрібно, ваша програма може якось "ініціалізуватися" - наприклад, встановити початкові значення змінних, прочитати якісь дані з файлів або Ini, створити елементи керування і так далі. Після виходу з процедури OnInit наша програма не закінчується! Тепер Політ при виникненні певної події викликатиме її обробник - процедуру нашої програми. Наприклад, такими подіями можуть бути черговий тік таймера, клік юзера на екранній кнопці, натиснення клавіші на клавіатурі і так далі. У цих процедурах-обробниках наша програма і робить якусь корисну роботу. Нарешті, коли Політ вирішив закрити нашу програму, він перед цим викличе процедуру-обробник OnClose (де ми можемо виконати якісь завершувальні дії типу звільнення пам'яті).

Дуже маленький приклад :). Розглянемо програмку, єдиною функцією якої буде вихід при натисненні будь-якої клавіші. На Паскалі під DOS це виглядатиме приблизно так:
Uses CRT;
Begin
  Repeat
  Until KeyPressed
End.
Добре видно структуру програми. Її виконання починається с початку операторної частини (після "Begin"). Після цього програма ця отримує комп у повне своє розпорядження, аж поки вона не дійде до кінця операторної частини (до "End.").

Аналогічна програма під Політ виглядатиме так. В операторній частині (між "Begin" та "End.") стоятиме один виклик Kernel.RegBuiltIn. Обробник OnInit не робитиме нічого (крім того, що вписав у нього Майстер програм). Обробник OnClose можна залишити таким, як зробив майстер програм, а можна взагалі прибрати - в ньому програма теж нічого не робитиме. Нам знадобиться ще обробник події OnKey - натиснення клавіші на клавіатурі. У ньому міститиметься один рядок:
Kernel.CloseProg(Me)
Тобто "закрити цю програму". Ось і вся програма. З одного боку програма вийде набагато більшою за DOS'івський аналог - цілих 1700 байт проти 52 байт. А з іншого боку майже всі ці 1700 байт напише Майстер програм, нам залишиться тільки вставити в процедуру OnKey рядок із CloseProg (20 літер). І не забувайте, у політівської програми при цьому буде вікно, яке можна рухати мишкою по екрану, міняти його розміри, навіть відкрити одночасно кілька вікон цієї програмки.

Сподіваюсь, що цей ліричний відступ допоміг вам зрозуміти принцип :).



Друга особливість політівських програм - це те, що робота з даними (змінними) в них організована досить хитро. На початку програми описаний тип-запис TTestAppData, всередині якого стоїить коментар: "Усі дані програми описуються тут, у цьому записі". І це дійсно так. Всі змінні треба описувати не у секції Var програми, як звичайно, а саме всередині цього запису. Це зроблено з таких міркувань. Політ - багатозадачна система; в ньому запросто можуть паралельно працювати кілька програм, і зобрема кілька копій одної програми (спробуйте запустити кілька копій нашої TestApp). Вони розділяють один на всіх екземпляр коду програми. Якщо б їх дані були описані в секції Var програми, вони б так само розділяли одні на всіх значення змінних (даних). Щоб цього не відбувалося, у Польоті для кожної копії програми відводиться пам'ять для власної копії даних. Ну, а для цього всі дані програми описані як один запис.

Фактично це реалізовано так. Ядро Польоту для кожної працюючої програми тримає запис типу TProg. В ньому зберігається різні дані про програму - координати її вікна, заголовок, іконка, адреси обробників, і зокрема вказівник на дані програми: Prog.Data^. Це нетипізований вказівник (бо у різних програм описи змінних різні). Тому до нього треба звертатися за допомогою приведення типу: TTestAppData(Prog.Data^). Наприклад, якщо у нас є змінна CounterProg - запис нашої програми), то до неї треба звертатися так: TTestAppData(Prog.Data^).Counter.

На перший погляд, це дуже незручно. Але насправді це незручно, але зовсім трошки :). В усі обробники як параметр передається вказівник на запис нашої програми - це Me:PProg (PProg=^TProg). А ще на початку кожного обробника відкривається блок приєднання:
With Me^, TTestAppData(Data^) Do ...
Отже, всередині обробників ми можемо звертатися до своїх змінних напряму (наприклад, просто Counter)! І тут Майстер програм зробив брудну роботу за нас :).

Залишається ще одне питання - як же звертатися до даних із звичайних процедур та функцій програми, не обробників? Тут нам доведеться вручну зробити те саме, що уже зроблено з обробниками:
  1. Передавати їм як додатковий параметр вказівник на запис нашої програми (Me:PProg).
  2. Брати ці процедури та функції в аналогічний блок приєднання:
With Me^, TTestAppData(Data^) Do ...
Тобто наші процедури та функції мають виглядати приблизно так:
Procedure MyProc(Me:PProg; Param1,Param2:Integer);
Begin
  With TTestAppData(Me^.Data^) Do
  Begin
    ...
    Counter:=1;
    ...
  End
End;


Це ніби і всі особливості політівських програм у цілому. Ще треба буде розповісти вам більше про події та їх обробники - які вони бувають, для чого призначені, як ними користуватися. Розповідати доведеться і правда досить багато, тому давайте виділимо для цього окремий, наступний розділ.