Фотография | Компьютеры | Программы | Эсперанто | Кровное
Перевод Д.Бречалова
Оригинальный текст вы можете найти по адресу: http://wiki.python.org/moin/JonathanGardnerPyQtTutorial
Это короткий учебник (tutorial) по работе с библиотекой PyQt. Предполагается, что вы имеете некоторые знания по bash, Python и Qt.
Если у вас есть вопросы или комментарии (относительно английского оригинала), вы можете послать их на jgardner-AT-jonathangardner.net. Вы также можете непосредственно вносить исправления в данный текст. (Также имеется в виду английский оригинал, опубликованный на Python Wiki. Комментарии и предложения по поводу русского перевода пишите здесь, в комментариях под страницей.)
Перевод Родриго Б. Виейра (Rodrigo B. Vieira) на (бразильский) португальский доступен по адресу http://www.pythonbrasil.com.br/moin.cgi/TutorialPyQt.
Мы рассмотрим:
Вам потребуются:
PyQt работает также на других системах. Приемы и программы, приведенные в руководстве могут не работать совсем или работать не надлежащим образом. Однако я не привожу всех деталей как заставить их работать на всех системах, которые могут использовать PyQt. Вы должны разобраться с этим сами.Также вы должны знать:
Если вы не удовлетворяете этим требованиям, у вас могут возникнуть некоторые трудности при изучении этого руководства.
Первым делом о главном. Начнем, пожалуй, с начала. Откройте окно bash-консоли. Запустите Qt Desiger следующей командой:
$ designer
Вас приветсвует Qt Designer. В зависимости от версии, имеющейся у вас, его внешний вид может немного различаться.
Могу предположить, что вы совершенно не знаете, как пользоваться Qt Designer'ом. Если это так, вы легко можете изучить документауию.
Создайте новый компонент (виджет – widget). Назовите его 'at-auto'. Наполните его “внутренностями”:
Теперь расположите элементы по своему вкусу, используя инструмент Qt layout. Для этого вам могут понадобиться несколько “распорок” (spacers).
Сохраните файл в каталоге проекта для этого руководства. Создайте каталог, если вы еще не сделали этого, и назовите его как-нибудь вроде “pyqt_tutorial”. Сохраните файл под именем “at.ui”.
Вернитесь назад в окно консоли или откройте новое. Перейдите в каталог проекта и запустите следующую команду:
$ pyuic at.ui
Следующая команда запишет сгенерированный на основании файла at.ui код на Питоне в файл at_auto.py:
$ pyuic at.ui -o at_auto.py
После каждого изменения ui-файла, нужно перегенерировать at_auto.py. Давайте поручим это команде make.
Табуляции важны!
$ cat > Makefile at_auto.py : at.ui pyuic at.ui -o at_auto.py ^D
Теперь запустите make:
$ make
Заметьте, что эта команда рапортует только о файлах, измененных со времени предыдущего запуска. Давайте обновим файл at.ui, чтобы он стал более новым, чем at_auto.py, и попробуем снова.
$ touch at.ui $ make
Теперь make печатает на экране команды, которые выполняет. Вы видите, что at_auto.py перегенерирован успешно.
Основная идея здесь состоит в том, чтобы дать возможность разработчику GUI вносить изменения в дизайн (например, переместить элемент интерфейса на другое место) без влияния на логику приложения. Так что, если вы все сделаете правильно, единственное, что должен сделать разработчик GUI, это внести изменения в файл at.ui, после чего запустить make чтобы его изменения вступили в силу.
Ваш make-файл будет становиться все более сложным по мере того, как вы будете добавлять все новые и новые файлы. Будьте готовы прочитать множество документации по утилите make, чтобы принять правильные решения при разработке о том, как правильно использовать make.
Итак, у нас есть файлы at.ui и at_auto.py. Как же нам теперь запустить приложение?
Мы должны создать at.py. Вот, как он должен выглядеть.
#!/usr/bin/env python from qt import * from at_auto import at_auto class at(at_auto): def __init__(self, parent=None, name=None, fl=0): at_auto.__init__(self,parent,name,fl) if __name__ == "__main__": import sys a = QApplication(sys.argv) QObject.connect(a,SIGNAL("lastWindowClosed()"),a, SLOT("quit()")) w = at() a.setMainWidget(w) w.show() a.exec_loop()
Теперь запустите его.
$ python at.py
Вуаля! Вот наше приложение.
Примечание
Если вы используете Qt designer с Qt версии 3.3.0, ваш .ui-файл содержит такой заголовок:
<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
и pyuic (по крайней мере 3.8.1) жалуется, что версия слишком новая для него, и что он не может обработать ее.
Исправить это легко: сделайте маленький скрипт, который будет автоматически исправлять эту ошибку, запускать make, а затем и ваше приложение:
#!/bin/bash sed -i s/3.3/3.3.0/g at.ui make exec python at.py
Затем сделайте его исполняемым: chmod 700 myscript.
Давайте установим значение по умолчанию для компонента QDateTimeEdit. Метод setDateTime компонента QDateTimeEdit ожидает объект класса QDateTime в качестве аргумента. Значит нужно его создать, но как задать время для QDateTime? Изучая документацию, мы обнаруживаем, что метод setTime_t позволит нам установить дату со временем в секундах с начала эпохи Unix. Мы можем его получить от функции time() стандартного встроенного модуля time.
Вот код, который делает это. Мы поместим его в конструктор init, чтобы дата со временем устанавливались правильно с самого начала. Не забудьте импортировать time!
# Set the date to now now = QDateTime() # Time in seconds since Unix Epoch now.setTime_t(time.time()) self.time.setDateTime(now)
Этот отрывок кода показывает, как легко работают друг с другом Питон и PyQt. Также он должен продемонстрировать мыслительный процесс, который вы должны пройти чтобы работать с компонентами Qt.
Все, чем вы будете теперь заниматься – это соединять Сигналы со Слотами. Это оченю просто, за что я и люблю PyQt.
Питон – не C++. Поэтому он должен обращаться с Сигналами и Слотами по-своему.
Во-первых, в Питоне слотом может быть любой вызываемый (исполняемый, callable) объект. Это может быть метод объекта, функция или даже лямбда-выражение. Во-вторых, сигнал в Питоне – просто лишенный смысла текст.
Позвольте мне объяснить различие между Сигналами/Слотами в C++ и Питоне. Там, где создается объект, делать нечего, все должно делаться там, где возникает Сигнал и там, где расположен Слот. Например, QPushButton имеет Сигнал C++ “clicked()”. Если вы создаете ваш собственный подкласс на Питоне, например, “PyPushButton”, он также имеет Сигнал C++ “clicked()”. Если вы создадите новый сигнал на Питоне, скажем, “GobbledyGook()”, это будет Сигнал Питона, так как ничто в C++ даже не знает о его существовании.
Когда вы связываете сигнал со слотом, вы можете выбрать одну из следующих возможностей:
Связать Сигнал C++ со Слотом Питона
Вы будете заниматься этим весь день напролет. Это делается примерно так:
QObject.connect(some_object, SIGNAL('toggled(bool)'), some_python_callable)
Связать Сигнал C++ со Слотом C++
Вы не часто будете это делать, тем не менее это искуссный прием.
QObject.connect(some_object, SIGNAL('toggled(bool)'), some_object, SLOT('the_slot(bool)'))
Связать Сигнал Питона со Слотом C++ или Питона
Вряд ли вы будете часто использовать Сигналы Питона, но мы опишем, как это делать. Придумайте имя нового сигнала. Затем поменяйте в примере выше “SIGNAL” на “PYSIGNAL”.
Может оказаться оправданным обойти сигнальную библиотеку Qt и испозльзовать вашу собственную, если вы используете большое количество сигналов Питона. Однако, если вы намереваетесь когда-нибудь переписать код на C++, это не имеет смысла. Я это сделал, потому что нашел синтаксис обременительным и трудным для отладки.
Наше приложение будет отвечать только на один сигнал: нажатие на кнопку “Schedule”. При этом оно будет запускать команду “at” с соответствующими аргументами.
Вот код для соединения сигнала со слотом:
self.connect( self.schedule, SIGNAL('clicked()'), self.schedule_clicked )
Заметьте, что мы соединяем сигнал C++ со слотом Питона. Однако, этот слое еще не существует. Давайте добавим его в класс 'at'.
def schedule_clicked(self): if not str(self.command.text()): QMessageBox.critical(self, "Invalid event", "You must specify an event", QMessageBox.Ok) return t = str(self.time.dateTime().toString('hh:mm MM/dd/yyyy')) p = os.popen('at -m "%s"'%t, 'w') p.write(str(self.command.text())) self.close()
Этот процесс состоит из двух частей. Сначала мы проверяем введено ли что-нибудь в строку ввода “command”. Если нет, мы показываем сообщение об ошибке при помощи QMessageBox.
Если в строке ввода что-то есть, мы открываем канал (pipe) с командой 'at'. 'at' ожидает ввода команды с sdtin. Затем мы пишем в ее stdin команду, которую хотим исполнить. Заметьте, что здесь мы не делаем никаких проверок на возможные ошибки.
Идем вперед и запускаем наше приложение, затем используем команду 'atq' чтобы посмотреть задание, поставленное в очередь 'at'.Получилось? Хорошо.
Вот окончательный вариант 'at.py'.
#!/usr/bin/env python from qt import * from at_auto import at_auto import time import sys import os class at(at_auto): def __init__(self, parent=None, name=None, fl=0): at_auto.__init__(self,parent,name,fl) # Set the date to now now = QDateTime() # Time in seconds since Unix Epoch now.setTime_t(time.time()) self.time.setDateTime(now) self.connect( self.schedule, SIGNAL('clicked()'), self.schedule_clicked ) def schedule_clicked(self): if not str(self.command.text()): QMessageBox.critical(self, "Invalid event", "You must specify an event", QMessageBox.Ok) return t = str(self.time.dateTime().toString('hh:mm MM/dd/yyyy')) p = os.popen('at -m "%s"'%t, 'w') p.write(str(self.command.text())) self.close() if __name__ == "__main__": a = QApplication(sys.argv) QObject.connect(a,SIGNAL("lastWindowClosed()"),a,SLOT("quit()")) w = at() a.setMainWidget(w) w.show() a.exec_loop()
В оставшееся время вы можете внести некоторые усовершенствования.
Это приложение могло бы стать частью пакета интерфейсов к консольным командам Unix. Какими еще командами вы хотели бы заняться? Я бы порекомендовал попробовать “crontab” и “ps”. Парсинг вывода этих команд не очень сложен и взаимодействовать с ними очень легко.
Вы также можете попытаться объединить ваше новое приложение с только что созданным 'at'. Если хотите, можете продавать их вместе как графический интерфейс Unix, но в этом случае вы должны будете приобрести коммерческие лицензии на Qt и PyQt, если вы не собираетесь придерживаться лицензии, подобной GPL.