Pull to refresh

Быстрая разработка GUI приложений на Ruby

Reading time5 min
Views27K

Вступление


На хабре, по-моему, уже почти все возможные графические API для руби рассматривались. Но почему-то все воспринимают и подают эти самые API исключительно как чистый код. Никаких тебе графических дизайнеров, никакой скоростной разработки GUI — сиди, вычисляй координаты ручками, подгоняй как надо. А зачем иначе, ведь на руби серьезных GUI приложений не написать.
А вот и нет! Если уж на то пошло, то на руби можно написать даже Wolfenstein. Но начинать лучше все-таки с чего-то менее глобального :)

Подготовка


Итак, попробуем написать что-нибудь не очень простое, достаточно GUI'евое и желательно не заморачиваясь на вычисление координат.
Для начала нам понадобится:
  • Ruby — собственно сам руби, если у вас его еще нет
  • Рубигемы WxRuby и WxSugar (ставятся командами «gem install wxruby» и «gem install wx_sugar» соответственно) — гем WxWidgets'ов и руби-утилитка wxSugar
  • wxFormBuilder — удобный GUI редактор

Дизайн


Все скачали, поставили. Можно написать… ну, пусть будет простая RSS читалка :)
Начнем с того самого пресловутого дизайна — запускаем FormBuilder и создаем новый проект, обзываем его как-нибудь. Далее добавляем в проект из закладки Forms самый обычный Frame.

Должно появиться обычное такое окошко. Прописываем ему красивый заголовок в свойствах, делаем рамочку какую хотим. И вот тут небольшой нюанс — чтобы мы могли создавать на его основе свое приложение, оно должно иметь свой subclass, поэтому идем все в те же свойства и задаем там что-нибудь вроде RubyRSSFrame.
Окно создали. Теперь надо добавить элементы управления. Что нам нужно для RSS читалки? Да, в общем-то, немного: ввод URL, кнопку «Добавить», список добавленных фидов, список тем в фиде и окошко для новостей.
Начинаем добавлять, но не торопимся — чтобы элементы располагались так, как нам надо, они должны быть в sizer'ах. Подробнее о том, что такое sizer'ы и как ими правильно пользоваться можно почитать, например вот тут. Находятся они в закладке Layout.

Поэтому сначала добавим общий sizer, а в него еще несколько мелких. И уже в них добавляем наши элементы: TextCtrl, Button, пару ListBox'ов и HtmlWindow. Для удобства можно задать всем этим элементам какие-нибудь понятные имена.
После всех проделанных действий должно получиться что-то вроде этого:


Теперь нам надо сгенерировать XRC файл. Идем в свойства проекта и выбираем там вместо генерации c++ кода, геренацию xrc. И нажимаем File — Generate Code (или просто F8). Получаем на выходе наш файл mainframe.xrc. XRC — это такой универсальный формат рисования WxWidgets окон, основанный на XML. Просто так он с Ruby работать не будет.
И вот тут нам на помощь приходит тот самый WxSugar. Открываем консоль, переходим в папку с нашей xrc'шкой и вводим команду «xrcise -o mainframe.rb mainframe.xrc». После ее выполнения, мы получим руби файл, описывающий наше окошко. Внимание! Без XRC файла он работать не будет!
Дизайн нарисовали, осталось его оживить :)

Программируем


Создаем новый руби файл, например "rubyrss.rb" и открываем его в редакторе. Для начала подключим все нужные гемы и нашу гуйню:
require 'wx' # гем wxruby
require 'rss/2.0' # гем для работы с rss2.0
require 'open-uri' # гем для работы с сетью
require 'mainframe' # наш дизайн


* This source code was highlighted with Source Code Highlighter.

Теперь нам надо создать форму и инициализировать приложение:
# Создаем наш класс, который наследует класс нарисованной формы
class RubyRSSMainFrame < RubyRSSFrame
 # Инициализация класса
 def initialize
  # Вызов инициализации родителя
  super
 end
end

# Запуск приложения на основе нашего класса
Wx::App.run do
 RubyRSSMainFrame.new.show
end


* This source code was highlighted with Source Code Highlighter.

При исполнении этого кода должно появляться нарисованное окошко. Естественно, оно будет статично — никаких действий.
Теперь создадим внутри класса несколько массивов для записи информации из RSS:
# Классовые массивы для данных RSS
# Массив с адресами

$rss_addr_arr = Array.new()
# Массив с топиками
$rss_topics_arr = Array.new()
# Массив с текстами
$rss_text_arr = Array.new()


* This source code was highlighted with Source Code Highlighter.

И добавим действие для кнопки. В процедуру инициализации вписываем строчку, добавляющую event listener на нажатие:
# add_btn - id кнопки
# addrss - имя нашей функции

evt_button(add_btn){ addrss }


* This source code was highlighted with Source Code Highlighter.

Теперь к самой функции, срабатывающей при нажатии:
 # Функция обработки добавления адреса RSS
 def addrss
  # Добавляем в массив адресов новый адрес, введенный в TextCtrl
  $rss_addr_arr << http_adress_input.value
  # Записываем позицию адреса в массиве
  position = $rss_addr_arr.length - 1

  # Добавляем новые массивы топиков
  $rss_topics_arr << Array.new()
  # и текстов
  $rss_text_arr << Array.new()

  # Открываем ссылку RSS'а
  feed_url = http_adress_input.value
  open(feed_url) do |http|
   # Считываем ответ
   response = http.read
   # Парсим ответ с помощью RSS парсера
   result = RSS::Parser.parse(response, false)
   # Добавляем в список загруженных фидов название
   rss_list.insert_items([result.channel.title],position)
   # Обрабатываем результаты
   result.items.each_with_index do |item, i|
    # Добавляем в массивы тему
    $rss_topics_arr[position] << item.title
    # и текст
    $rss_text_arr[position] << item.description
   end
  end


* This source code was highlighted with Source Code Highlighter.

Теперь наша программа загружает фид и выводит его название. Осталось совсем немного — сделать, чтобы показывались списки тем новостей и текст новостей.
Добавляем еще два event listener'а на выбор элементов в ListBox'ах:
evt_listbox(rss_list) { | event | readnews }
evt_listbox(topics_list) { | event | shownews }


* This source code was highlighted with Source Code Highlighter.

И прописываем соответствующие простенькие функции:
 # Вывод списка новостей по фиду
 def readnews
  # Очищаем старый список
  topics_list.clear
  # Берем ID выделенного фида
  rssid = rss_list.get_selections[0]
  # Каждый элемент массива топиков
  $rss_topics_arr[rssid].each do |item|
   # добавляем в список топиков
   topics_list.insert_items([item],0)
  end
 end

 # Показываем текст новости
 def shownews
  # Берем ID выдевеленного фира
  rssid = rss_list.get_selections[0]
  # Берем ID выделенной новости
  topicid = topics_list.get_selections[0]
  # Показываем текст
  news_text_html.set_page($rss_text_arr[rssid][topicid])
 end


* This source code was highlighted with Source Code Highlighter.

Вот и все. Итоговый результат должен выглядеть примерно так:


Итоги


Вся разработка заняла не больше 10 минут. И это при моем довольно среднем знании Ruby.
Да, это приложение нельзя назвать завершенным — в нем наверняка много ботлнеков и всяческих глюков. Но цель была не создать полноценное приложение, а показать, что и на Ruby вполне можно разрабатывать GUI приложения, причем достаточно быстро.

upd. Перенес в блог Ruby. Спасибо за отзывы :)
Tags:
Hubs:
Total votes 54: ↑50 and ↓4+46
Comments35

Articles