неділю, 13 травня 2012 р.

QtRuby: позиціювання віджетів

У цій статті, ми познайомимося з основами розміщенням віджетів у вікні додатку QtRuby.

Коли ми розробляємо графічний інтерфейс додатку, ми вирішуємо, які компоненти ми будемо використовувати і як ми будемо організовувати ці компоненти. Щоб організувати компоненти, ми використовуємо спеціальні невидимі ​​об'єкти, так звані менеджери компонування(layout managers).
Qt надає кілька варіантів. Ми можемо використовувати абсолютне позиціювання, вбудовані менеджери компонування або створити власний менеджер компонування. Також ми також можемо візуально будувати макети допомогою Qt Designer.

Абсолютне позиціювання.


Негарний і не рекомендований метод розміщення графічних об'єктів - "в ручну" задавати положення і розмір кожного віджета у пікселях, використовуючи метод setGeometry(x, y, width, height).
# -*- encoding: utf-8 -*-

require 'Qt'

class QtApp < Qt::Widget
  def initialize
    super

    set_window_title 'Absolute'

    init_ui

    resize 400, 280
    move 300, 300

    show
  end

  def init_ui
    label = Qt::Label.new('Windows', self)
    edit = Qt::TextEdit.new(self)
    activate = Qt::PushButton.new('Activate', self)
    close = Qt::PushButton.new('Close', self)
    ok = Qt::PushButton.new('OK', self)
    help = Qt::PushButton.new('Help', self)

    label.move(10, 10)
    edit.set_geometry(10, 30, 300, 200)
    activate.set_geometry(320, 30, 70, 30)
    close.set_geometry(320, 60, 70, 30)
    ok.set_geometry(320, 240, 70, 30)
    help.set_geometry(10, 240, 70, 30)
  end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec


Очевидний недолік такого підходу проявиться відразу ж, як тільки ви почнете змінювати розміри вікна. Всі віджети залишаються на своїх місцях.

Менеджери компонування

Qt надає більш гнучкий і досконалий механізм розміщення графічних об'єктів в контейнері. В Qt для цих цілей існують менеджери компонування, успадковані від класу Qt::Layout.
Розглянемо три основних менеджера компонування: Qt::HBoxLayout, Qt::VBoxLayout і Qt::GridLayout.
Для розміщення об'єктів в один ряд по горизонталі використовується Qt::HBoxLayout, аналогічно Qt::VBoxLayout - для розміщення об'єктів по вертикалі.
Для більш складних розміщень використовують Qt::GridLayout, а також комбінації з усіх трьох менеджерів.
Qt::GridLayout розміщує елементи в комірках уявної таблиці, причому кожен елемент може займати кілька суміжних комірок по вертикалі і/або горизонталі. Про нього пізніше.
Для додавання підлеглого віджету використовується метод addWidget(), для додавання підлеглого менеджера компонування - метод addLayout().

# -*- encoding: utf-8 -*-

require 'Qt'

class QtApp < Qt::Widget
  def initialize
    super

    set_window_title 'Layouts'

    init_ui

    resize 400, 280
    move 300, 300

    show
  end

  def init_ui
    label = Qt::Label.new('Windows', self)
    edit = Qt::TextEdit.new(self)
    activate = Qt::PushButton.new('Activate', self)
    close = Qt::PushButton.new('Close', self)
    ok = Qt::PushButton.new('OK', self)
    help = Qt::PushButton.new('Help', self)

    vbox = Qt::VBoxLayout.new(self)

    vbox1 = Qt::VBoxLayout.new
    hbox1 = Qt::HBoxLayout.new
    hbox2 = Qt::HBoxLayout.new

    vbox.add_widget(label)

    vbox1.add_widget(activate)
    vbox1.add_widget(close, 0, Qt::AlignTop)
    hbox1.add_widget(edit)
    hbox1.add_layout(vbox1)

    vbox.add_layout(hbox1)

    hbox2.add_widget(help)
    hbox2.add_stretch(1)
    hbox2.add_widget(ok)

    vbox.add_layout(hbox2, 1)

    set_layout(vbox)

  end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec


vbox = Qt::VBoxLayout.new(self)
Базовий блок нашого прикладу, у якому будуть розміщуватися всі інші віджети і блоки.

vbox.add_widget(label)
Першим йде віджет мітки(label). Він буде просто знаходитися зверху у вертикальному блоці(vbox).

vbox1.add_widget(activate)
vbox1.add_widget(close, 0, Qt::AlignTop)

hbox1.add_widget(edit)
hbox1.add_layout(vbox1)

vbox.add_layout(hbox1)
У центральній частині вікна у нас є віджет редагування тексту(edit) і дві кнопки(activate і close). Вони розміщені у вертикальному блоці(vbox1), і вирівняні по верхній його частині. Віджет редагування тексту(edit) і вертикальний блок(vbox1) розміщені у горизонтальному блоці(hbox1), який в свою чергу розміщений у вертикальному блоці(vbox) відразу під віджетом мітки(label).

hbox2.add_widget(help)
hbox2.add_stretch(1)
hbox2.add_widget(ok)

vbox.add_layout(hbox2, 1)
Кнопки help і ok розміщені в іншому горизонтальному блоці(hbox2). Між ними за допомогою методу addStretch() встановлений розширювальний пробіл. Знову ж таки, горизонтальний блок(hbox2) розміщений в головному вертикальному блоці(vbox).

set_layout(vbox)
Головний вертикальний блок(vbox) встановлений, як основний для вікна.

Можете переконатися, що віджети позиціонуються відносно розмірів вікна.

В останньому прикладі ми будемо використовувати менеджер Qt::GridLayout.
# -*- encoding: utf-8 -*-

require 'Qt'

class QtApp < Qt::Widget
  def initialize
    super

    set_window_title 'GridLayout'

    init_ui

    resize 400, 280
    move 300, 300

    show
  end

  def init_ui
    label = Qt::Label.new('Windows', self)
    edit = Qt::TextEdit.new(self)
    activate = Qt::PushButton.new('Activate', self)
    close = Qt::PushButton.new('Close', self)
    ok = Qt::PushButton.new('OK', self)
    help = Qt::PushButton.new('Help', self)

    grid = Qt::GridLayout.new(self)

    grid.add_widget(label, 0, 0)
    grid.add_widget(edit, 1, 0, 3, 2)
    grid.add_widget(activate, 1, 2)
    grid.add_widget(close, 2, 2)
    grid.add_widget(ok, 4, 2)
    grid.add_widget(help, 4, 0)

    grid.set_column_stretch(1, 1)
    grid.set_row_stretch(3, 1)

    set_layout(grid)
  end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec


grid.add_widget(label, 0, 0)
Ми розміщуємо мітку(label) в першу клітинку сітки. Клітинки рахуються від 0. Останні два параметри є номерами рядка і стовпця.

grid.add_widget(edit, 1, 0, 3, 2)
Віджет редагування тексту(edit) поміщається в першому рядку і нульовому стовпці. Останні два параметри є діапазоном рядків і стовпців. Вертикально, віджет буде охоплювати три рядка, а горизонтально - дві колонки.

grid.set_column_stretch(1, 1)
Параметрами методу setColumnStretch() є номер колонки і коефіцієнт розтягування. Тут ми встановлюємо коефіцієнт розтягування 1 для першої колонки. Це означає, що ця колонка буде займати все вільне місце по горизонталі. Це зроблено для, щоб кнопки зберігали свій оригінальний розмір.

grid.set_row_stretch(3, 1)
Аналогічно тут встановлюємо коефіцієнт розтягування 1 для третього рядка, щоб мітка(label) зберігала свій мінімальний розмір.

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