Вступление
На хабре, по-моему, уже почти все возможные графические 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. Спасибо за отзывы :)