Прелюдия.
Как-то давно нужно было написать GUI к парсеру с Яндекс-словари (перевод). Что самое Ъ? Конечно же Ruby. Подумал я тогда. Но как же я был удивлен, когда практически не нашел русской документации и примеров, чтобы познакомиться с GUI-программированием. Да и англоязычная не очень помогла: все какие-то коротки обрывки и заметки типа hello_world'ов. Это относится к Qt. На сайте Qt Disigner'a до сих пор пример под Qt3. Пришлось написать ГУЙ на GTK+, и то переплевался — документация на сайте модуля неполная, недописанная, без примеров…
Недавно понадобилось написать GUI-приложения. Но к этому времени познакомившись с основой Python — решил посмотреть как он в отношение GUI. А в часности Qt4, т.к. я сам кедераст :), да и Qt4 уже сменяет Qt3. Во всяком случает на моём десктопе. И был я приятно удивлен — что много для Python примеров, документации, в т.ч. и на русском языке по этой части. И наткнулся я на сборку хороших примеров для Python+QT4 на странице: www.rkblog.rk.edu.pl/w/p/python — к примеру — написание текстового редактора с нуля. Где все подробно в примерах все разобрано. Посидел 2 вечера, разобрался с основой, и написал свою программулину.
И потом сижу и думаю все хорошо в том примере, да и Python почти тот же Ruby. Нужно сделать Ъ вещь, переписать примеры на русский язык и под Ruby. Что собственно сейчас и делаю.
И так, поехали.
Простой тестовый редактор. Ч. 1
Сейчас мы напишем простой текстовый редактор (просмотрщик для начала).
Нам понадобится ruby1.8 и rbuic4. Причем при установке последнего должены будут поставиться необходимые библиотеки по работе с Qt4 в ruby.
Интерфейс будет делаться в Qt Designer (designer-qt4)
В Qt Designer создаем новую форму, основанную на «Main Window».
На форму помещаем 2 кнопки типа «Push Button» и поле для редактирования текста — «Text Edit»

Для первой кнопки установим текст — «Открыть файл»: через свойство «text» в окне Property Editor или по двойному клику на кнопке.
Так же установим для неё ObjectName — «b_open»: опять же через Property Editor или в контекстном меню выбрав Change objectName.
Для главной формы objectName я установил как — «notepad», а для Text Edit как «editor_window»
Для второй кнопки установим название «закрыть» и objectName — «b_close». Кнопка что должна делать? Правильно, закрывать окно. В QT-Disigner'a в окне Signal/Slot Editor добавим новый слот:
Sender -> b_close
Signal -> clicked()
Receive -> notepad
Slot -> close()
И сохраняем проект как editor.ui
Теперь выполним команду:
для того, чтобы получить класс Ruby — Ui_Notepad.
Опция -x добавляет инструкции в файл для запуска приложения. Можно сейчас запустить форму, чтобы убедиться что всё работает:
опции -Ku предназначены для коррекной обработки UTF-8.
Но тут есть одна тонкость — если мы будем вносить какие-то изменения в интерфейс — будет переписываться файл editor.rb. Поэтому мы создадим отдельный скрипт, который будет вызывать форму, назовем его start.rb.
Перегенерируем форму: rbuic4 editor.ui > editor.rb, и напишем start.rb следующим образом:
Сейчас кнопка «закрыть» — работает. Пора настроить кнопку «открыть».
Внесем изменения в start.rb
Если запустить приложение — при нажатии на кнопку ('clicked()') вызывается слот 'file_dialog()', и в свою очередь вызывается метод file_dialog, который вставляет текст 'aaaaaaaa' в EditText'у.
Сейчас мы используем Qt::FileDialog для выбора файла. Следующий код:
f.getOpenFileName покажет диалог выбора файла, который закрывается после выбора файла (и возвращается путь к файлу), прерывая выполнения кода. Это работает, но если мы нажмем «отмена» при работе окна f.getOpenFileName мы не получим пути к файлу, но получим следущую ошибку:
start.rb:17:in `initialize': can't convert nil into String (TypeError)

Т.е. если файл не выбран — возвращается nil. Следующий код включает проверку возвращаемого значения:
Сейчас мы можем выбрать файл, но не можем сохранить его. Давайте добавим кнопку «сохранить» в QTDesign'e и назначем objectName — 'b_save', и перегенерируем GUI из нового ui-файла:
Сейчас приложение выглядит следующим образом:

Мы добавим слот для сохранения файла и создадим коннект ему с сигналом «clicked()» на pushButton-кнопку «сохранить:

И так мы получили приложение, которое открывает текстовые файлы и сохраняет изменения в этом файле.
В следующей заметке будет расширены возможности приложения.
Я запускал приложение на Ubuntu 8.10, проблем с кодировкой не обнаружилось, при этом не забываем про ключи ruby -Ku для поддержки UTF-8.
З.Ы. Прости за форматирование кода, в первый раз пост пишу. Вроде теги <code></code>, а все съехало влево. Буду благодарен, если подскажете как привильно оформлять код.
З.З.Ы. Пока еще плохо разбираюсь в терминологии Qt. Так же буду рад, если проккоментируете что такое „коннект“, „слот“
Как-то давно нужно было написать GUI к парсеру с Яндекс-словари (перевод). Что самое Ъ? Конечно же Ruby. Подумал я тогда. Но как же я был удивлен, когда практически не нашел русской документации и примеров, чтобы познакомиться с GUI-программированием. Да и англоязычная не очень помогла: все какие-то коротки обрывки и заметки типа hello_world'ов. Это относится к Qt. На сайте Qt Disigner'a до сих пор пример под Qt3. Пришлось написать ГУЙ на GTK+, и то переплевался — документация на сайте модуля неполная, недописанная, без примеров…
Недавно понадобилось написать GUI-приложения. Но к этому времени познакомившись с основой Python — решил посмотреть как он в отношение GUI. А в часности Qt4, т.к. я сам кедераст :), да и Qt4 уже сменяет Qt3. Во всяком случает на моём десктопе. И был я приятно удивлен — что много для Python примеров, документации, в т.ч. и на русском языке по этой части. И наткнулся я на сборку хороших примеров для Python+QT4 на странице: www.rkblog.rk.edu.pl/w/p/python — к примеру — написание текстового редактора с нуля. Где все подробно в примерах все разобрано. Посидел 2 вечера, разобрался с основой, и написал свою программулину.
И потом сижу и думаю все хорошо в том примере, да и Python почти тот же Ruby. Нужно сделать Ъ вещь, переписать примеры на русский язык и под Ruby. Что собственно сейчас и делаю.
И так, поехали.
Простой тестовый редактор. Ч. 1
Сейчас мы напишем простой текстовый редактор (просмотрщик для начала).
Нам понадобится ruby1.8 и rbuic4. Причем при установке последнего должены будут поставиться необходимые библиотеки по работе с Qt4 в ruby.
Интерфейс будет делаться в Qt Designer (designer-qt4)
В Qt Designer создаем новую форму, основанную на «Main Window».
На форму помещаем 2 кнопки типа «Push Button» и поле для редактирования текста — «Text Edit»

Для первой кнопки установим текст — «Открыть файл»: через свойство «text» в окне Property Editor или по двойному клику на кнопке.
Так же установим для неё ObjectName — «b_open»: опять же через Property Editor или в контекстном меню выбрав Change objectName.
Для главной формы objectName я установил как — «notepad», а для Text Edit как «editor_window»
Для второй кнопки установим название «закрыть» и objectName — «b_close». Кнопка что должна делать? Правильно, закрывать окно. В QT-Disigner'a в окне Signal/Slot Editor добавим новый слот:
Sender -> b_close
Signal -> clicked()
Receive -> notepad
Slot -> close()
И сохраняем проект как editor.ui
Теперь выполним команду:
rbuic4 editor.ui -x > editor.rb
для того, чтобы получить класс Ruby — Ui_Notepad.
Опция -x добавляет инструкции в файл для запуска приложения. Можно сейчас запустить форму, чтобы убедиться что всё работает:
ruby -Ku editor.rb
опции -Ku предназначены для коррекной обработки UTF-8.
Но тут есть одна тонкость — если мы будем вносить какие-то изменения в интерфейс — будет переписываться файл editor.rb. Поэтому мы создадим отдельный скрипт, который будет вызывать форму, назовем его start.rb.
Перегенерируем форму: rbuic4 editor.ui > editor.rb, и напишем start.rb следующим образом:
require 'Qt4'
require 'editor.rb'
class StartQT4 < Qt::MainWindow
def initialize parent=nil
super
@ui = Ui_Notepad.new
@ui.setupUi self
end
end
if $0 == __FILE__
app = Qt::Application.new(ARGV)
myapp = StartQT4.new
myapp.show
app.exec
end
Сейчас кнопка «закрыть» — работает. Пора настроить кнопку «открыть».
Внесем изменения в start.rb
require 'Qt4'
require 'editor.rb'
class StartQT4 < Qt::MainWindow
#тут подключаем слот
slots 'file_dialog()'
def initialize parent=nil
super
@ui = Ui_Notepad.new
@ui.setupUi self
#не знаю как по русски сказать, что тут мы делаем.
# here we connect signals with our slots
Qt::Object.connect(@ui.b_open, SIGNAL('clicked()'), self, SLOT('file_dialog()'))
end
#метод, который выполняет при нажатии на кнопку.
def file_dialog
@ui.editor_window.setText 'aaaaaaa'
end
end
if $0 == __FILE__
app = Qt::Application.new(ARGV)
myapp = StartQT4.new
myapp.show
app.exec
end
Если запустить приложение — при нажатии на кнопку ('clicked()') вызывается слот 'file_dialog()', и в свою очередь вызывается метод file_dialog, который вставляет текст 'aaaaaaaa' в EditText'у.
Сейчас мы используем Qt::FileDialog для выбора файла. Следующий код:
require 'Qt4'
require 'editor.rb'
class StartQT4 < Qt::MainWindow
slots 'file_dialog()'
def initialize parent=nil
super
@ui = Ui_Notepad.new
@ui.setupUi self
Qt::Object.connect(@ui.b_open, SIGNAL('clicked()'), self, SLOT('file_dialog()'))
end
def file_dialog
f = Qt::FileDialog
text = File.new(f.getOpenFileName).read
@ui.editor_window.setText text
end
end
if $0 == __FILE__
app = Qt::Application.new(ARGV)
myapp = StartQT4.new
myapp.show
app.exec
end
f.getOpenFileName покажет диалог выбора файла, который закрывается после выбора файла (и возвращается путь к файлу), прерывая выполнения кода. Это работает, но если мы нажмем «отмена» при работе окна f.getOpenFileName мы не получим пути к файлу, но получим следущую ошибку:
start.rb:17:in `initialize': can't convert nil into String (TypeError)

Т.е. если файл не выбран — возвращается nil. Следующий код включает проверку возвращаемого значения:
require 'Qt4'
require 'editor.rb'
class StartQT4 < Qt::MainWindow
slots 'file_dialog()'
def initialize parent=nil
super
@ui = Ui_Notepad.new
@ui.setupUi self
Qt::Object.connect(@ui.b_open, SIGNAL('clicked()'), self, SLOT('file_dialog()'))
end
def file_dialog
f = Qt::FileDialog
if @filename = f.getOpenFileName
text = File.new(@filename).read
@ui.editor_window.setText text
end
end
end
if $0 == __FILE__
app = Qt::Application.new(ARGV)
myapp = StartQT4.new
myapp.show
app.exec
end
Сейчас мы можем выбрать файл, но не можем сохранить его. Давайте добавим кнопку «сохранить» в QTDesign'e и назначем objectName — 'b_save', и перегенерируем GUI из нового ui-файла:
rbuic4 editor.ui > editor.rb
Сейчас приложение выглядит следующим образом:

Мы добавим слот для сохранения файла и создадим коннект ему с сигналом «clicked()» на pushButton-кнопку «сохранить:
require 'Qt4'
require 'editor.rb'
class StartQT4 < Qt::MainWindow
slots 'file_dialog()', 'file_save()'
def initialize parent=nil
super
@ui = Ui_Notepad.new
@ui.setupUi self
Qt::Object.connect(@ui.b_open, SIGNAL('clicked()'), self, SLOT('file_dialog()'))
Qt::Object.connect(@ui.b_save, SIGNAL('clicked()'), self, SLOT('file_save()'))
end
def file_dialog
f = Qt::FileDialog
if @filename = f.getOpenFileName
text = File.new(@filename).read
@ui.editor_window.setText text
end
end
def file_save
if @filename
f = File.new @filename, 'w'
f.puts @ui.editor_window.toPlainText
f.close
end
end
end
if $0 == __FILE__
app = Qt::Application.new(ARGV)
myapp = StartQT4.new
myapp.show
app.exec
end

И так мы получили приложение, которое открывает текстовые файлы и сохраняет изменения в этом файле.
В следующей заметке будет расширены возможности приложения.
Я запускал приложение на Ubuntu 8.10, проблем с кодировкой не обнаружилось, при этом не забываем про ключи ruby -Ku для поддержки UTF-8.
З.Ы. Прости за форматирование кода, в первый раз пост пишу. Вроде теги <code></code>, а все съехало влево. Буду благодарен, если подскажете как привильно оформлять код.
З.З.Ы. Пока еще плохо разбираюсь в терминологии Qt. Так же буду рад, если проккоментируете что такое „коннект“, „слот“