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

Сайт Польоту
 

Елементи керування
Лінія розділу - Splitter (модуль Ctl)

Лінія розділу - це така полосочка, яку звичайно кладуть між різними частинами вікна і яку юзер може рухати мишкою (відповідно міняючи розміри частин вікна). Можна, я далі для краткості називатиму її спліттером? Запустіть Файл-менеджер; лінія посередині між панельками - це і є спліттер, його можна тягати мишкою ліворуч та праворуч, і панелі відповідно мінятимуть свої (горизонтальні) розміри. Спліттери бувають вертикальні (як у Файл-менеджері) та горизонтальні.

Принцип роботи зі спліттерами такий. Із кожним спліттером пов'язане число - поточне положення спліттера (тобто координата X у вікні для вертикального спліттера та координата Y - для горизонтального). Коли юзер переміщує спліттер, він відповідно міняє значення своєї координати та викликає перемалювання свого вікна. Отже, нам треба тільки після створення спліттера (та завдання його початкового положення) малювати все в OnPaint з урахуванням його положення.

Політівські спліттери мають декілька відмінностей від Windows'них. По-перше, вони можуть бути активними та керуватися з клавіатури, стрілочками. Якщо це не заборонити, як зроблено у Файл-менеджері. По-друге, на них можуть бути показані стрілочки; при цьому клік на спліттері (не перетягування, а окремий клік) буде або пересувати спліттер у крайнє положення (в бік, указаний стрілками), або повертати його з крайнього положення в попереднє.




Створити спліттер
Function Splitter_Create(Prog:PProg; 
  VPos:Integer; VOrient:TOrientation; 
  VArrows:TSplitterArrows): PControl;
  • VPos - положення (координата) спліттера у вікні, X або Y залежно від його орієнтації.
  • VOrient - орієнтація спліттера (orHorizontal - горизонтальна, orVertical - вертикальна).
  • VArrows - стрілки спліттера. Від цього параметра залежить, чи будуть на спліттері стрілки і чи реагуватиме він на окремий клік. Можливі значення: saNone - нема стрілок та реакції на клік; saLeftUp - стрілки ліворуч або вгору (залежно від VOrient), окремий клік працює; saRightDown - стрілки праворуч або вниз, окремий клік працює.


Намалювати спліттер
Procedure Splitter_Paint(Me:PControl; 
  VX1,VY1,VX2,VY2:Integer);
VX1, VY1, VX2, VY2 - координати прямокутника, в якому може рухатись спліттер.
  • Якщо він вертикальний, VY1 та VY2 - це координати Y його верхнього та нижнього країв, а VX1 та VX2 - відповідно найменша та найбільша координата X, між якими може бути його положення.
  • Відповідно якщо спліттер горизонтальний, тоді VX1 та VX2 - координати X його країв, а VY1 та VY2 - межі Y, між якими може змінюватись його позиція.


Отримати положення спліттера
Function Splitter_GetCoord(Me:PControl): Integer;
Зверніть увагу: для вертикального спліттера ця функція повертає його координату X, а для горизонтального - Y.



Не дуже зрозуміло? Так і повинно бути :). Зараз ми зробимо приклад на ці полосочки, і все стане більш прозорим. Давайте придумувати форму для прикладу... Хай у нижній її частині буде канва, зафарбована темно-сірим; вона буде іти від самого низу форми до горизонтального спліттера. А над ним буде ще вертикальний спліттер, що розділятиме поле вводу та кнопку. Хай перший (горизонтальний) спліттер має стрілочки, а вертикальний - ні. Отже, робимо заготовку TestSpl та описуємо змінні:
InpTest, SplVer, BtnTest: PControl;
SplHor: PControl;
CanTest: PControl;
Створюємо елементи керування (хай розміри вікна залишаться за умовчанням - 350 х 240 пікселів):
InpTest:=Ctl.InpLine_Create(Me, 'Test', Nil);
SplVer:=Ctl.Splitter_Create(Me, 210, orVertical,
  saNone);
BtnTest:=Ctl.Button_Create(Me, 'Test', Nil, ppLeft,
  Kernel.CtlDummyProc);
SplVer:=Ctl.Splitter_Create(Me, 120, orHorizontal,
  saLeftUp);
CanTest:=Ctl.Canvas_Create(Me, False, False);
Тут ми вказали початкові положення спліттерів - горизонтальний по центру вікна, вертикальний трохи правіше центра. Тепер головне - малювання вікна. Основний принцип такий - першими малюємо спліттери, а потім інші елементи керування, положення яких залежить від спліттерів. Тут у нас особливий випадок - довжина вертикального спліттера залежить від положення горизонтального; тому малюємо спочатку горизонтальний, потім (залежний від нього) вертикальний, а потім (залоежні від них обох) елементи керування.

Малюються спліттери не так, як більшість інших елементів керування. Для них ми вказуємо не положення, а прямокутник, всередині якого може "їздити" спліттер. Для горизонтального спліттера це буде, скажімо, (5, 40, X2-X1-5, Y2-Y1-20) - по горизонталі він ітиме від лівого края вікна до правого, а по вертикалі їздитиме від положення трохи нижче поля вводу та кнопки і майже до самого низу вікна. Із вертикальким трохи складніше - він ітиме від верху вікна до горизонтального спліттера; тобто його Y1 та Y2 вдіповідно будуть 5 та Ctl.Splitter_GetCoord(SplHor). Ну а по горизонталі хай він їздить від 50 до X2-X1-50; отже, маємо прямокутник (50, 5, Ctl.Splitter_GetCoord(SplHor), X2-X1-50).

Зрозуміли, як юзати цей Splitter_GetCoord? Саме так ми робимо і з іншими елементами керування, положення яких залежить від положення спліттера - замість відповідної координати беремо поточне положення спліттера. Отже, наш обробник OnPaint остаточно матиме такий вигляд:
Procedure TestSpl_OnPaint(Me:PProg);
Begin
  With Me^, TTestSplData(Me^), ClientRect Do
  Begin
    Ctl.Splitter_Paint(SplHor, 5, 40, X2-X1-5, Y2-Y1-20);
    Ctl.Splitter_Paint(SplVer, 50, 5, 
      Ctl.Splitter_GetCoord(SplHor), X2-X1-50);
    Ctl.InpLine_Paint(InpTest, 10, 10,
      Ctl.Splitter_GetCoord(SplVer)-10);
    Ctl.InpLine_Paint(BtnTest, 
      Ctl.Splitter_GetCoord(SplVer)+10, 10, X2-X1-10);
    Ctl.Canvas_Paint(CanTest, 5, 
      Ctl.Splitter_GetCoord(SplHor)+5, X2-X1-5, Y2-Y1-5);
    With CanTest^.Place Do
      Gfx.Bar(X1, Y1, X2, Y2, clGray)
  End
End;