Книга: Программирование на языке Ruby

12.2.5. Прочие виджеты

12.2.5. Прочие виджеты

Даже для организации сравнительно простого графического интерфейса текстовых полей и кнопок может оказаться недостаточно. Нужны переключатели, флажки и другие виджеты. В следующем примере демонстрируются некоторые из них.

В листинге 12.7 предполагается, что пользователь хочет заказать билет на самолет. Для выбора города назначения используются классы Gtk::TreeView, Gtk::ListStore и Gtk::TreeViewColumn (многоколонный список). Флажок (класс Gtk::CheckButton) определяет, нужен ли обратный билет, а переключатель (класс Gtk::RadioButton) позволяет указать класс салона. Завершает интерфейс кнопка Purchase (Заказать) — рис. 12.6.

Листинг 12.7. Заказ билета на самолет

$KCODE = "U"
require "gtk2"
class TicketWindow < Gtk::Window
 def initialize
  super("Purchase Ticket")
  signal_connect("destroy") { Gtk.main_quit }
  dest_model = Gtk::ListStore.new(String, String)
  dest_view = Gtk::TreeView.new(dest_model)
  dest_column = Gtk::TreeViewColumn.new("Destination",
   Gtk::CellRendererText.new,
   :text => 0)
  dest_view.append_column(dest_column)
  country_column = Gtk::TreeViewColumn.new("Country",
   Gtk::CellRendererText.new,
   :text => 1)
  dest_view.append_cоlumn(country_cоlumn)
  dest_view.selection.set_mode(Gtk::SELECTION_SINGLE)
  [["Cairo", "Egypt"], ["New York", "USA"],
   ["Tokyo", "Japan"]].each do |destination, country|
   iter = dest_model.append
   iter[0] = destination
   iter[1] = country
  end
  dest_view.selection.signal_connect("changed") do
   @city = dest_view.selection.selected[0]
  end
  @round_trip = Gtk::CheckButton.new("Round Trip")
  purchase = Gtk::Button.new("Purchase")
  purchase.signal_connect("clicked") { cmd_purchase }
  @result = Gtk::Label.new
  @coach = Gtk::RadioButton.new("Coach class")
  @business = Gtk::RadioButton.new(@coach, "Business class")
  @first = Gtk::RadioButton.new(@coach, "First class")
  flight_box = Gtk::VBox.new
  flight_box.add(dest_view).add(@round_trip)
  seat_box = Gtk::VBox.new
  seat_box.add(@coach).add(@business).add(@first)
  top_box = Gtk::HBox.new
  top_box.add(flight_box).add(seat_box)
  main_box = Gtk::VBox.new
  main_box.add(top_box).add(purchase).add(@result)
  add(main_box)
  show_all
 end
 def cmd_purchase
  text = @city
  if @first.active?
   text += ": first class"
  elsif
   @business.active?
   text += ": business class"
  elsif @coach.active?
   text += ": coach"
  end
  text += ", round trip " if @round_trip.active?
  @result.text = text
 end
end
Gtk.init
TicketWindow.new
Gtk.main


Рис. 12.6. Различные виджеты GTK

В этом приложении, как и в предыдущих примерах, создается главное окно с обработчиком события. Затем формируется список с двумя колонками, дизайн которого следует паттерну Модель-Вид-Контроллер (Model-View-Controller — MVC); класс Gtk::ListStore (модель) имеет две колонки типа String.

Далее создается виджет Gtk::TReeView. Класс Gtk::treeViewColumn конфигурирует эту колонку. Первая колонка называется «Destination», а для отображения клеток применяется класс рисовальщика Gtk::CellRendererText. Первая колонка модели (с номером 0) — Gtk::ListStore — служит значением текстового свойства. Итак, рисовальщики клеток наполняют древесную модель данными. В GTK+ 2.x есть несколько готовых рисовальщиков клеток, в том числе Gtk::CellRendererText, Gtk::CellRendererPixbuf и Gtk::CellRendererToggle. Далее в список добавляются три строки данных и устанавливается обработчик события "changed", который будет вызываться, когда пользователь выберет другую строку. Этот обработчик изменит значение переменной @city, записав в нее текст из первой колонки только что выбранной строки.

Затем создается простой флажок (Gtk::CheckButton) и кнопка (Gtk::Button). Обработчик события нажатия кнопки вызовет метод cmd_purchase. Метка @result первоначально пуста, но позже в нее будет записана строка, определяющая вид заказанного билета.

Три переключателя создаются как члены одной группы, то есть в любой момент может быть выбран лишь один из них. Когда пользователь щелкает по любому переключателю, равнее выбранный сбрасывается. Первым параметром конструктору переключателя передается первый переключатель из той же группы. Поэтому у конструктора первого переключателя в группе этого параметра нет, а остальным передается ссылка на первый переключатель.

Виджеты нужно организовать на экране так, чтобы пользователю было удобно. Мы воспользовались комбинацией контейнеров Gtk::НВох и Gtk::VBox. Список расположен над флажком. Все три переключателя расположены вертикально справа от списка. А кнопка помещена под всеми остальными виджетами.

Метод cmd_purchase очень прост: он строит строку, отражающую состояние всех виджетов в момент нажатия кнопки. У переключателей и флажков есть метод active?, который возвращает true, если виджет отмечен. Построенная строка записывается в метку @result и потому появляется на экране.

Во многих приложениях интерфейс содержит меню. В следующем примере показано, как можно организовать меню в Ruby/GTK2. Заодно демонстрируется применение всплывающих подсказок — мелкая деталь, способная украсить любую программу.

В листинге 12.8 создается главное окно с меню, содержащим пункт File и еще два фиктивных пункта. В меню File есть команда Exit, которая завершает приложение. Оба пункта File и Exit снабжены всплывающими подсказками.

Листинг 12.8. Пример меню в GTK

$KCODE = "U"
require "gtk2"
class MenuWindow < Gtk::Window
 def initialize
  super("Ruby/GTK2 Menu Sample")
  signal_connect("destroy") { Gtk.main_quit }
  file_exit_item = Gtk::MenuItem.new("_Exit")
  file_exit_item.signal_connect("activate") { Gtk.main_quit }
  file_menu = Gtk::Menu.new
  file_menu.add(file_exit_item)
  file_menu_item = Gtk::MenuItem.new("_File")
  file_menu_item.submenu = file_menu
  menubar = Gtk::MenuBar.new
  menubar.append(file_menu_item)
  menubar.append(Gtk::MenuItem.new("_Nothing"))
  menubar.append(Gtk::MenuItem.new("_Useless"))
  tooltips = Gtk::Tooltips.new
  tooltips.set_tip(file_exit_item, "Exit the app", "")
  box = Gtk::VBox.new
  box.pack_start(menubar, false, false, 0)
  box.add(Gtk::Label.new("Try the menu and tooltips!"))
  add(box)
  set_default_size(300, 100)
  show_all
 end
end
Gtk.init
MenuWindow.new
Gtk.main

И здесь базовая структура программы такая же, как в предыдущих примерах. В данном случае мы создаем пункт меню Gtk::MenuItem с именем Exit и задаем для него обработчик события, который завершает программу. Событие называется activate и генерируется, когда пользователь выбирает пункт меню.

Далее создается меню File и в него добавляется пункт Exit. Это все, что требуется для создания выпадающего меню. В конце создается пункт меню File; именно он и появится в полосе меню. Чтобы присоединить пункт File к меню File, мы вызываем метод submenu=.

Затем создается полоса меню Gtk::MenuBar, в которую добавляются три меню: File, Nothing и Useless. Что-то делает лишь первое меню, остальные приведены только для демонстрации.

Всплывающими подсказками управляет единственный объект Gtk::Tooltips. Чтобы создать подсказку для любого виджета, например для пункта меню, нужно вызвать метод set_tip, которому передаются сам виджет, текст подсказки и строка, содержащая дополнительный скрытый текст. Скрытый текст не показывается в составе подсказки, но может, например, использоваться для организации оперативной справки.

Чтобы разместить полосу меню в верхней части главного окна, мы взяли Gtk::VBox в качестве самого внешнего контейнера. В данном случае мы добавляем в него полосу меню не методом add, а методом pack_start, чтобы точнее контролировать внешний вид и положение виджета.

Первым параметром методу pack_start передается размещаемый виджет. Второй параметр — булевский признак, показывающий, должен ли виджет занимать все доступное пространство. Отметим, что виджет при этом не растет, а обычно просто размещается в центре контейнера. Мы хотим, чтобы полоса меню располагалась сверху, поэтому передаем false.

Третий параметр — тоже булевская величина, говорящая о том, должны ли размеры виджет быть изменены так, чтобы он занял все отведенное пространство. Нам нужна лишь узкая полоса меню, поэтому мы и тут передаем false. Последний параметр метода pack_start задает отступы, то есть пустое место вокруг виджета. Нам это ни к чему, поэтому мы передаем нуль.

Большую часть главного окна занимает метка. Напоследок мы принудительно устанавливаем размер окна 300?100 пикселей.

Оглавление книги


Генерация: 0.039. Запросов К БД/Cache: 0 / 2
поделиться
Вверх Вниз