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

Сайт Польоту
 

Елементи керування
Список - ListBox (модуль Ctl2)

Найсмачніше - на десерт :). Знайомтесь - мій улюблений елемент керування, список.

Список - останній із трійки так званих "великих" елементів керування (разом із полем вводу та текстовим редактором). Принципи роботи списка зовсім нескладні, на відміну, скажімо, від текстового редактора. Але він натомість підтримує величезну купу опцій, режимів та наворотів. А саме:
  • підтримка багатьох колонок (стовпчиків) із різним вирівнюванням, в тому числі невидимих;
  • іконки та відступи для елементів списка;
  • сортування елементів за алфавітом або будь-яким іншим критерієм;
  • різноманітні події, на які можна вішати обробники: вибір (клік), подвійний клік, клік правою кнопкою, хінт.
І як результат - дуже багато процедур та функцій для роботи з ним, цілих 25 штук. Не варто лякатись; насправді ніхто не примушує використовувати їх усі, для простого списка досить трьох-чотирьох процедур. А коли цього стане мало, тоді вам стануть у пригоді всі ці advanced features...

Списки використовуються в Польоті багато де - зокрема у Файл-менеджері, у діалогу відкриття та збереження файлів, на Навігаційній панелі, у Менеджері задач, у настройках екрана, програмках "Принтер", "Друзі"... Коротше кажучи, багато де :).




Створити список
Function ListBox_Create(Prog:PProg; 
  VMultiSelect:Boolean): PControl;
Так, дійсно, для створення списка достатньо лише одного параметра (крім Prog, звісно). Але список буде поки що порожнім; додавати до нього елементи я навчу вас далі.
VMultiSelect - флажок, чи підртимуватиме список одночасний вибір кількох елементів. False - ні, лише один елемент списка може бути обраним (той, на якому стоїть курсор). True - так, перед елементами показуються маленькі флажки, і клікаючи по них юзер може відмічати скільки завгодно елементів списка (хоч усі, хоч 0).



Намалювати список
Procedure ListBox_Paint(Me:PControl; 
  VX1,VY1,VX2,VY2:Integer);
VX1, VY1, VX2, VY2 - координати списка у вікні.



Додати елемент у кінець списку
Procedure ListBox_AddItemLast(Me:PControl; 
  VName:String; VIcon:Pointer; VIndent:Byte);
  • VName - текст елемента.
  • VIcon - вказівник на картинку елемента.
  • VIndent - відступ елемента (тобто на скільки пікселів правіше лівого краю списка малюватиметься елемент). Для елементів без відступу вказуйте тут 0.


Додати елемент у початок списку
Procedure ListBox_AddItemFirst(Me:PControl; 
  VName:String; VIcon:Pointer; VIndent:Byte);
Елемент додається у першу позицію списка; якщо в ньому уже були елементи, вони всі зсуваються вниз.
  • VName - текст елемента.
  • VIcon - вказівник на картинку елемента.
  • VIndent - відступ елемента.


Додати елемент у список другим
Procedure ListBox_AddItemSecond(Me:PControl; 
  VName:String; VIcon:Pointer; МIndent:Byte);
Елемент додається у другу позицію списка; при потребі елементи від другого до останнього зсуваються вниз.
  • VName - текст елемента.
  • VIcon - вказівник на картинку елемента.
  • VIndent - відступ елемента.


Додати елемент у відсортований список
Procedure ListBox_AddItemSorted(Me:PControl; 
  VName:String; VIcon:Pointer; МIndent:Byte);
Якщо ваш список відсортований (або порожній), ця процедура вставить елемент у ту позицію, де він повинен бути за критерієм сортування. Наприклад, якщо у нас є список із елементами від "1" до "9", то AddItemSorted("73") вставить "73" між "7" та "8". Інше використання - у порожній список вставляти всі елементи цією процедурою; тоді в будь-який момент (в ході додавання елементів) список буде відсортованим. Якщо список не відсортований, AddItemSorted додасть у нього елемент, але куди?.. :)
Критерій сортування задається процедурою SetSortFunc (див. далі), критерій за умовчанням - по алфавіту за назвами.
  • VName - текст елемента.
  • VIcon - вказівник на картинку елемента.
  • VIndent - відступ елемента.


Додати піделемент
Procedure ListBox_AddSubItem(Me:PControl; 
  VName:String; VIcon:Pointer);
Що таке піделемент? Дуже просто - якщо ви додаєте до елемента списка піделемент, він показується у другій колонці (у тому ж рядку). Викликається ця процедура відразу після додавання елемента, до якого ми хочемо додати піделемент. Ось так і створюються списки з багатьма колонками. AddSubItem можна виконувати кілька разів підряд, щоб зробити кілька колонок. Приклади шукайте у Файл-менеджері, Менеджері задач.
  • VName - текст елемента.
  • VIcon - вказівник на картинку елемента.
Як бачите, відступи для піделементів не підтримуються.



Відсортувати список
Procedure ListBox_Sort(Me:PControl);
Критерій сортування за умовчанням - по алфавіту за назвами (якщо у списку багато колонок, то по першій). Цей критерій можна заміняти на власний, дивіться далі SetSortFunc.



Видалити елемент зі списка
Procedure ListBox_DeleteItem(Me:PControl; N:Integer);
N - номер елемента. Нумеруються елементи починаючи з 1.



Знайти елемент за текстом
Function ListBox_FindItem(Me:PControl;
  VName: String): Integer;
Функція шукає у списку елемент із текстом VName (у першій колонці списка) та повертає номер знайденого елемента або 0, якщо не нічого не знайшла.



Вибрати елемент списка
Procedure ListBox_SelectItem(Me:PControl; 
  VSelItemNum:Integer);
VSelItemNum - номер елемента, який треба зробити вибраним (тобто поставити на нього курсорну рамку). Елементи нумеруються, починаючи з 1.



Отримати номер вибраного елемента списка
Function ListBox_GetSelItemIndex(Me:PControl): Integer;
Якщо не вибрано жоден елемент, повертає 0.



Отримати елемент списка за індексом
Function ListBox_GetItemByIndex(Me:PControl; Index:Integer): 
  PListItem;
Index - номер елемента (починаючи з 1).
Функція повертає вказівник на елемент списка типу TListItem. Цей тип описаний у модулі Ctl2 так:
TListItem=Record
  Name: PStr;              { Текст елемента }
  Selected: Boolean;       { Флажок: чи вибраний елемент }
  Indent: Byte;            { Відступ елемента }
  Icon: Pointer;           { Іконка елемента }
  SubItem, Next: PListItem { Піделемент та наступний елемент }
End;
Принаймні вам не завадить знати, що коли Item має тип PListItem, тоді String(Item^.Name^) - це текст елемента :).



Отримати вибраний елемент списка
Function ListBox_GetSelItem(Me:PControl): PListItem;


Отримати прямокутник вибраного елемент асписка
Procedure ListBox_GetSelItemRect(Me:PControl; Var R:TRect);
R - координати на екрані вибраного елемента списка. Це використовується, наприклад, у Файл-менеджері для анімації при зміні папки.



Отримати кількість відмічених елементів списка
Function ListBox_GetSelItemsTotal(Me:PControl): Integer;
Якщо список підтримує мульти-вибір (MultiSelect), ця функція повертає кількість елементів, на яких юзер поставив відмітку.



Переконатись, що вибраний елемент видимий
Procedure ListBox_ScrollToViewSelItem(Me:PControl);
Процедура перевіряє, чи видимий зараз вибраний елемент списка, і якщо ні, прокручує список так, щоб він став видимим. Цю процедуру корисно викликати після SelectItem; так робить Файл-менеджер при поверненні у попередню папку (при кліку на "..").



Задати критерій сортування
Procedure ListBox_SetSortFunc(Me:PControl;
  VSortFunc:TListBoxSortFunc);
Іншими словами, установити функцію-обробник для події порівняння двох елементів списка, яка використовується при сортуванні. Тип TListBoxSortFunc описаний у Ctl2 так:
TListBoxSortFunc=Function(Me:PProg; 
  Item1,Item2:PListItem): Boolean;
Ця функція отримує вказівники на два елементи списка - Item1 і Item2. Функція має порівняти їх і повернути True, якщо Item1<Item2, і False в іншому випадку. Власний критерій сортування використовується зокрема у Файл-менеджері - він сортує свої списки за алфавітом, але спочатку ідуть папки, а потім файли. Дивіться також наступну функцію.



Функція-критерій сортування за умовчанням
Function ListBox_DefaultSortFunc(Me:PProg; 
  Item1,Item2:PListItem): Boolean;
Ця функція сортування використовується відразу після створення списка, поки не буде заданий власний критерій; якщо треба, після цього ще одним викликом SetSortFunc критерієм можна знову зробити цю функцію. Щоб ви мали уявлення, як має виглядати функція-критерій сортування, я наведу текст DefaultSortFunc:
Function ListBox_DefaultSortFunc(Me:PProg; 
  Item1,Item2:PListItem): Boolean;
Begin
	If String(Item1^.Name^)<String(Item2^.Name^)
		Then ListBox_DefaultSortFunc:=True
		Else ListBox_DefaultSortFunc:=False
End;


Установити обробник вибору елемента списка
Procedure ListBox_SetOnSelect(Me:PControl; 
  VOnSelect:TCtlHandler);
Вибір елемента - це коли рамка вибору опиняється на іншому елементі. Це може статися через натиснення на клавіатурі стрілок вгору та вниз, Home, End, PgUp, PgDn, в результаті пошуку по перших літерах, або при одиночному кліку лівою кнопкою мишки. Приклад - панель настройки екрана, найперша сторінка "Теми". Там у списку тем навішено обробник вибору елемента, який перемальовує зразок теми над списком.



Установити обробник "сильного" вибору елемента списка
Procedure ListBox_SetOnStrongSelect(Me:PControl; 
  VOnStrongSelect:TCtlHandler);
"Сильний" вибір - це або натиснення Enter'а, або подвійний клік мишкою. Через цю подію Файл-менеджер та Навігаційна панель відкривають папки та файли.



Установити обробник кліку правою кнопкою мишки
Procedure ListBox_SetOnContextMenu(Me:PControl; 
  VOnContextMenu:TCtlHandler);
Стандартна реакція на клік правою кнопкою мишки - показати контекстне меню клікнутого елемента. Саме так роблять Файл-менеджер та Менеджер задач. Але про показ меню я вам ще не розповідав (майже), це буде потім...



Установити обробник показу хінта
Procedure ListBox_SetOnHint(Me:PControl; 
  VOnHint:TListBoxHintHandler);
Якщо юзер зупиняє курсор мишки над списком та тримає його деякий час (до секунди), виникає оця подія. TListBoxHintHandler описаний у Ctl2 так:
TListBoxHintHandler=Procedure(Me:PProg; 
  Control:PControl; Item:PListItem);
Відразу після виходу з цього обробника кернел покаже хінт списка. Отже, обробник цей може якраз перед показом змінити хінт. Наприклад, показати детальну інформацію про елемент списка під курсором (параметр Item). Саме так робить Файл-менеджер. Хінт перевизначається так:
D.ReassignPStr('Новий текст хінта', Control^.Hint);


Установити параметри колонки (стовпчика) списка
Procedure ListBox_SetColumnProps(Me:PControl; 
  VColumnNum:Integer; VAlign:TListColumnAlign; 
  VVisible:Boolean);
Ця процедура звичайно викликається відразу після створення списка, разом із навішуванням обробників.
  • VColumnNum - новер колонки (стовпчика), для якого встановлюються параметри.
  • VAlign - вирівнювання написів у стовпчику: lcLeft - по лівому краю (за умовчанням), lcRight - по правому краю, lcRightMono - по правому краю, шрифт фіксованої ширини (зручно для чисел). lcRightMono використовує Файл-менеджер для показу розмірів файлів.
  • VVisible - видимість стовпчика: True - показується, False - не показується. Невидимі стовпчики зручно використовувати, коли треба для кожного елемента списка зберігати якісь дані, але показувати їх небажано.