суботу, 5 вересня 2009 р.

wxRuby → Сайзери (1 частина)

Під час створення графічного інтерфейсу, вам потрібно займатися розміщенням елементів на формі. Наприклад, вам може знадобитись текстове поле і кнопка справа під ним. Ви можете розмістити ці елементи керування(Wx::TextCrt і Wx::Button), чітко вказавши позицію і розміри у пікселях. Ймовірно це не найкраща ідея, але ви можете зробити це у будь-якому випадку:
# -*- encoding: utf-8 -*-

require 'wx'

class HelloFrame < Wx::Frame
def initialize
super(nil, :id => -1, :title => 'Hello World!', :size => [200, 200])
text = Wx::TextCtrl.new(self, :id => -1,
:text => 'Type in here',
:pos => [0, 0],
:size => [200, 175],
:style => Wx::TE_MULTILINE)
button = Wx::Button.new(self, :id => -1,
:label => 'Press me',
:pos => [100, 175],
:size => [100, 25])

show
end

end

class HelloApp < Wx::App
def on_init
HelloFrame.new
end
end

app = HelloApp.new
app.main_loop()


Результат виконання скрипта:



Чому це погана ідея? Спробуйте збільшити і зменшити розміри вікна. Елементи залишаються на своїх місцях.



wxWidgets використовує інший підхід до розміщення елементів на формі. Елементи розміщуються не лише по відношенню до верхнього лівого кута. Їхній розмір також задається по відношенню до висоти і ширини.
Тобто, повертаючись до прикладу із статті Welcome to wxRuby!, ми помістили у вікно лише одну кнопку, по замовчуванню вона має висоту і ширину рівну, відповідно, висоті і ширині вікна.

Замість організації віджетів, використовуючи точні розміри і позиції, можна використовувати так звані сайзери, тобто класи похідні від Wx::Sizer. Саме сайзери визначають поведінку дочірніх елементів при зміні розмірів головного вікна. На мою думку, сайзери є найбільш складною для освоєння частиною бібліотеки wxRuby. І саме сайзерам буде присвячена ця стаття.



Загальні відомості про сайзери.

Для того щоб краще зрозуміти, як користуватися сайзерами, їх найкраще уявити собі у вигляді книжкових полиць або шафок, розділених на секції. Всередині кожної секції може розміщуватися тільки один елемент. Ці елементи ви можете пересунути до лівої стінки полиці, так щоб справа залишилось вільне місце, або навпаки до правої. На відміну від книжок, елемент керування ви можете приклеїти до стелі, або примусити висіти по центру. На відміну від справжніх меблів, ці полички та шафки можуть розтягувати книжки, щоб вони займали все вільне місце.
Для початку розглянемо клас Wx::Sizer, який є базовим для всіх сайзерів. При створені інтерфейсу будуть використовуватись похідні від Wx::Sizer класи. Ви не можете безпосередньо використовувати Wx::Sizer. Замість цього використовуєте один із похідних від нього класів. На даний час це:

  • Wx::BoxSizer

  • Wx::StaticBoxSizer

  • Wx::GridSizer

  • Wx::FlexGridSizer

  • Wx::GridBagSizer


Варто пам'ятати, сайзери не є вікнами, тобто елементами керування, а тільки вміють змінювати розміщення і розміри своїх "підопічних" елементів.
Клас Wx::Sizer містить доволі багато методів, але нас в першу чергу цікавить тільки один - метод add(), за допомогою якого можна додати один елемент в "шафку". Слід зазначити, що всередині сайзеру замість елементу керування можна помістити інший сайзер. Завдяки цьому ми можемо розбити кожну "полицю" на декілька комірок.

Розглянемо параметри методу add()

Wx::SizerItem#add(Wx::Window window,
Integer proportion = 0,
Integer flag = 0,
Integer border = 0
Object user_data = nil)


item. У якості першого параметру можуть виступати 3 види об'єктів:

  • Елементи керування, а точніше вікна, похідні від класу Wx::Window

  • Інші сайзери, тобто класи, похідні від Wx::Sizer

  • Екземпляр класу Wx::Size(не плутати з Wx::Sizer), який представляє собою клас обгортку над двома числовими значеннями - шириною і висотою. Якщо в метод add() передати екземпляр класу Wx::Size, то замість елементу керування в комірку сайзера буде додане порожнє місце заданого розміру.



proportion. Цей параметр може використовуватись класом Wx::BoxSizer, про який ми поговоримо пізніше. При використанні цього параметру можна визначити як будуть змінюватись розміри елементів при зміні їх батьківського вікна. Якщо він рівний 0(значення по замовчуванню), то елемент буде займати мінімальний розмір. Якщо сайзер містить декілька елементів з однаковими значеннями proportion, то при зміні розмірів батьківського вікна, елементи будуть змінювати свої розміри таким чином, щоб мати однакові розміри відносно однієї із осей(яка це вісь, горизонтальна чи вертикальна, залежатиме від орієнтації сайзера). Якщо елементи будуть мати різні значення proportion, то їх розміри вздовж вісі будуть пропорційні значенням proportion.
flag. Це, мабуть, самий важливий параметр, який більше всіх визначає розміщення і розміри елементів керування. Є цілочисловим значенням, яке складається із набору констант. Всі ці константи умовно можна розділили на 3 групи:

  • Прапорці, які задають невидиму рамку навколо елементів керування.

  • Прапорці, які задають вирівнювання елементів керування.

  • Прапорці, які задають поведінку при зміні розмірів батьківського вікна.



До першої групи належать:

  • Wx::TOP

  • Wx::BOTTOM

  • Wx::LEFT

  • Wx::RIGHT

  • Wx::ALL


Вони задають з якої сторони від елементу керування буде невидима рамка: зверху, знизу, зліва, справа чи з усіх сторін відповідно. Рамка представляє собою порожнє місце, розмір якого задається у наступному параметрі методу add(). Якщо ми, наприклад, хочемо щоб зліва і справа від елементу було залишене порожнє місце, то прапорець повинен мати наступний вигляд:
Wx::LEFT | Wx::RIGHT

До прапорців, що задають вирівнювання елементів керування належать:

  • Wx::ALIGN_CENTER

  • Wx::ALIGN_LEFT

  • Wx::ALIGN_RIGHT

  • Wx::ALIGN_TOP

  • Wx::ALIGN_BOTTOM

  • Wx::ALIGN_CENTER_VERTICAL

  • Wx::ALIGN_CENTER_HORIZONTAL


Ці прапорці позначають відповідно, що елемент керування буде "приклеєний" до центру, до лівої або правої стінки, до верху або низу комірки. Останні два прапорці дають можливість зазначити, що вирівнювання по центру потрібно робити тільки по вертикалі або тільки по горизонталі, у той час як Wx::ALIGN_CENTER означає, що вирівнювання по центру буде проводитися по обох осях.

Крім того є ще три прапорці, які впливають не на розміщення, а на розмір елементів.

  • Wx::EXPAND позначає, що елемент повинен займати всю комірку сайзера на скільки він зможе розтягнутися.

  • Wx::SHAPED позначає, що елемент знову ж таки повинен зайняти по можливості всю комірку, але при цьому він повинен зберігати вихідні пропорції між його довжиною і шириною.

  • Wx::FIXED_MINSIZE означає, що при зміні розмірів елементу, не буде враховуватися мінімально можливий розмір, тобто елемент може бути меншим заданого мінімального розміру.



А тепер перейдемо до огляду інших параметрів методу add()
border. Цей параметр визначає розміри рамки у пікселях. Таким чином цей параметр необхідний у тому випадку, якщо використовуються прапорці з першої групи.
user_data. Представляє собою дані користувача, які можуть прикріплятися до елемента, щоб більш точно визначати розташування елементу. Наразі wxRuby не підтримує цей параметр.

Встановлення сайзера для вікна.
Припустимо, ми створили сайзер, заповнили його елементами керування або іншими сайзерами. Тепер головному вікну потрібно вказати, що створений сайзер потрібно використовувати для розміщення елементів.
Для цього у класу Wx::Window є метод set_sizer():
Wx::Window#set_sizer(Wx::Sizer sizer, Boolean delete_old = true)


Перший параметр представляє собою екземпляр сайзера.
Другий параметр delete_old позначає, що попередній сайзер, встановлений для вікна повинен бути знищеним. Значення по замовчуванню true.

Варто пам'ятати, що вікно буде розтягувати сайзер на всю доступну область, що нагадує використання прапорця Wx::EXPAND.

Отже, загальний алгоритм роботи з сайзерами складається з наступних етапів:

  1. Створити екземпляр вікна - батька для елементів керування

  2. Після створення вікна створити екземпляр одного із класів похідних від Wx::Sizer. Це буде головний для вікна сайзер.

  3. Заповнити головний сайзер елементами керування або іншими сайзерами.

  4. Приєднати головний сайзер до вікна за допомогою методу Wx::Window#set_sizer()


У якості прикладу створимо вікно з текстовим полем і однією кнопкою справа під ним. Але на відміну від прикладу, який наводився на початку статті, для позиціонування будемо використовувати сайзер Wx::BoxSizer.
# -*- encoding: utf-8 -*-

require 'wx'

class HelloFrame < Wx::Frame
def initialize
super(nil, :id => -1,:title => 'Hello World!', :size => [200, 200])
sizer = Wx::BoxSizer.new(Wx::VERTICAL)
text = Wx::TextCtrl.new(self, :id => -1,
:text => 'Type in here',
:pos => Wx::DEFAULT_POSITION,
:size => Wx::DEFAULT_SIZE,
:style => Wx::TE_MULTILINE)
button = Wx::Button.new(self, :id => -1,
:label => 'Press me')

sizer.add(text, 1, Wx::GROW|Wx::ALL, 2)
sizer.add(button, 0, Wx::ALIGN_RIGHT, 2)
set_sizer(sizer)

show
end
end

class HelloApp < Wx::App
def on_init
HelloFrame.new
end
end

app = HelloApp.new
app.main_loop()


Запустіть цей приклад і спробуйте змінити розміри вікна.





У наступній статті ми детальніше розглянемо сайзери, які існують в бібліотеці wxRuby і на прикладах побачимо як впливають на розміщення елементів всі прапорці з методу Wx::Sizer#add().

На все добре і успіхів.

Немає коментарів: