В этом примере мы создали собственный класс виджета с именем
MyWidget
, он наследует классу
Qt::Widget
, являющемуся предком любого нестандартного виджета.
Перед инициализацией мы подготовили список слотов, которые будут
определены в нашем классе. Слоты — это обычные методы класса, но необходимо указать их имена, чтобы во время выполнения QtRuby знала, что мы собираемся использовать их именно в качестве слотов. Метод класса
slots
принимает список строк:
slots = 'slot1', 'slot2'
Инициализатор класса принимает аргумент
parent
, он есть почти у всех виджетов в Qt и определяет, какой виджет будет владельцем вновь создаваемого. Значение
nil
означает, что это «виджет верхнего уровня», у которого нет владельца. Концепция «владения», наверное, имеет более понятный смысл в C++; родители владеют своими детьми, то есть при уничтожении или удалении родителя удаляются и все его потомки.
Наш класс создает объект
Qt::LineEdit
для ввода текста и кнопку
Qt::PushButton
с надписью
All Caps!
. В качестве родителя каждому виджету передается self. Это означает, что создаваемый экземпляр
MyWidget
«усыновляет» эти виджеты.
Далее мы обращаемся к ключевой части библиотеки Qt — механизму соединения сигналов со слотами. В классе
Qt::Pushbutton
определен сигнал
clicked
, который испускается при нажатии кнопки. Этот сигнал можно соединить со слотом, в данном случае с методом
buttonClickedSlot
. Имя слота может быть любым, суффикс
Slot
мы употребили просто для наглядности.
В самом конце мы создаем экземпляр класса
Qt::HBoxLayout
. При добавлении виджетов в этот контейнер он автоматически изменяет их размеры, так что нам больше не о чем беспокоиться.
12.4.4. Текстовые поля
Как видно из листинга 12.14, в QtRuby есть класс
Qt::LineEdit
для ввода одной строки текста. Для ввода нескольких строк предназначен класс
Qt::TextEdit
.
В листинге 12.15 демонстрируется многострочное текстовое поле. Под ним расположена метка, в которой отображается текущая длина текста (рис. 12.8).
@textedit.insertPlainText("This really is an editor")
connect(@textedit, SIGNAL('textChanged'),
self, SLOT('theTextChanged'))
end
def theTextChanged
text = "Length: " + @textedit.toPlainText.length.to_s
@status.setText(text)
end
end
app = Qt:Application.new(ARGV)
widget = MyTextWindow.new
widget.setWindowTitle("QtRuby Text Editor")
widget.show
app.exec
Рис. 12.8.
Простой редактор в Qt
Виджет конструируется примерно так же, как в предыдущем примере. Но теперь мы создаем объект
Qt::TextEdit
, а также метку
Qt::Label
для показа текущего состояния.
Стоит отметить, что для объекта
@textedit
мы указали шрифт Times высотой 24 пункта. У каждого класса, наследующего
Qt::Widget
(в том числе и у
Qt::TextEdit
) есть свойство
font
, которое можно опросить или установить.
Затем мы создаем менеджер вертикального размещения (
Qt::QBoxLayout
), который будет контейнером для всех своих потомков, добавляем в него виджет
@textedit
и связываем сигнал
textChanged
с определенным нами слотом
theTextChanged
.
В методе
theTextChanged
мы запрашиваем у редактора текст и получаем его длину, а затем записываем возвращенное значение в метку
@status
.
Отметим, что весь механизм сигналов и слотов работает асинхронно. После того как приложение входит в цикл обработки событий (
арр.ехес
), оно уже не получает управления явно. Вот почему сигналы и слоты так важны. Мы определяем события, которые нас интересуют (сигналы), и действия, которые нужно выполнить при возникновении таких событий (слоты).
12.4.5. Прочие виджеты
В библиотеке Qt есть еще много встроенных виджетов, например переключатели, флажки и т.п. В листинге 12.16 продемонстрированы некоторые из них, а на рис. 12.9 показано, как выглядит окно приложения.
Листинг 12.16. Прочие виджеты в Qt
require 'Qt'
class MyWindow < Qt::Widget
slots 'somethingClicked(QAbstractButton *)'
def initialize(parent = nil)
super(parent)
groupbox = Qt::GroupBox.new("Some Radio Button",self)