Пользователь
0,0
рейтинг
14 ноября 2009 в 15:18

Разработка → Разговариваем про PyQt4 — Посиделка первая

image

Небольшое вступление


    Собственно, тогда, давно, я решил попробовать Qt, потому что часто слышал об удобстве разработки под него и своими глазами видел, какая шикарная документация представлена на сайте производителя. Не могу сказать, что это далось легко (я раньше немного писал на GTK), особенно путался в этих бесконечных классах на "Q", но постепенно начало нравиться все больше и больше. В частности потому, что есть отличная привязка к нему для языка Python, на котором я, собственно, в основном и пишу.
    Еще почему? Ну, я мог бы рассказать и о том, что он работает как на почти всех настольных системах, так и на многих мобильных, рассказать про совершенно гениальную объектную систему виджетов и т. п. Но — зачем? Не люблю холивары с приверженцами других визуальных библиотек :) Поэтому давайте считать этот топик чем-то вроде дележки опытом и рассуждений на тему.

Ну, поехали...


    В силу особенностей современного образования, многие программисты молодого поколения (к коим себя причисляет и ваш покорный слуга) живут с вколоченными в голову Pascal'ем и Delphi. Ну а что, ведь удобно — рисуешь мышкой окошки, связываешь компоненты, прописываешь им методы — и в минимальные сроки получаешь красивое оконное приложение. Я сам довольно долго сидел на них, даже делал пару фриланс-проектов. Но в один прекрасный день что-то щелкнуло в голове — и на ноутбуке вместо сверкающей Vista поселилась коричневая Ubuntu. Не буду рассказывать, почему и как я выбрал Python, но однажды возникла потребность вылезти из черных недр консоли и написать кое-что оконное.
    Как для Qt, так и для GTK существуют свои визуальные редакторы, интерфейс которых буквально интуитивно понятен не только бывшему делфятнику, но и разработчику, решившему сунуться в десктопную разработку первый раз. Для GTK это Glade, для Qt — идущий в комплекте с SDK инструмент Qt Designer. Причем оба они существуют как в виде самостоятельных приложений, так и как плагины к небезызвестной и нежно мной любимой среде Eclipse, а еще для Qt недавно появилась очень и очень неплохая нативная IDE — Qt Creator, которую тоже включили в SDK. Единственный минус — пока что не существует вменяемого плагина, позволяющего использовать ее для разработки на Python. На выходе у обоих — файл с xml-структурой, чем-то напоминающий по своему назначению dfm-файлы Delphi. То есть их можно положить в папку с проектом и подключить несколькими строками кода — и все практически готово.
    Для пущего удобства существует пакет-посредник между Qt Designer и Python и носит он имя pyqt4-dev-tools, а внутри него лежит программка pyuic4, служащая для удобной трансляции ui-файлов «дизайнера» в чистенький и опрятненький Python-код. НО! Как обычно в этой жизни, здесь не работает старый добрый принцип «нажмешь кнопку и красиво». Более того, я очень не советую вам употреблять pyuic4 для серьезных проектов. Почему? Сейчас расскажу.
    Pyuic4 — совершенно незаменимая вещь при освоении PyQt4. Что может быть удобнее — бросил пару виджетов на форму, транслировал получившийся файл одной командой в Python-скрипт — и уже ковыряешь код, смотря, какие методы вызываются при создании виджетов, обращении к ним, создании надписей и т. д. Но pyuic4 также генерирует кучу ненужного, на мой взгляд, кода, без которого можно обойтись и сделать все удобнее и компактнее без потери читабельности и удобства. Вот пример кода, генерируемого pyuic4 для простейшей формы с двумя кнопками и полем ввода (и да, не ругайте меня за стандартные имена для виджетов, это всего лишь пример :) ):
Copy Source | Copy HTML
  1. # -*- coding: utf-8 -*-
  2.  
  3. # Form implementation generated from reading ui file '/home/username/Рабочий стол/habr.ui'
  4. #
  5. # Created: Fri Nov 13 23:52:05 2009
  6. #      by: PyQt4 UI code generator 4.6
  7. #
  8. # WARNING! All changes made in this file will be lost!
  9.  
  10. from PyQt4 import QtCore, QtGui
  11.  
  12. class Ui_MainWindow(object):
  13.     def setupUi(self, MainWindow):
  14.         MainWindow.setObjectName("MainWindow")
  15.         MainWindow.resize(226, 146)
  16.         self.centralwidget = QtGui.QWidget(MainWindow)
  17.         self.centralwidget.setObjectName("centralwidget")
  18.         self.lineEdit = QtGui.QLineEdit(self.centralwidget)
  19.         self.lineEdit.setGeometry(QtCore.QRect(10, 10, 201, 26))
  20.         self.lineEdit.setObjectName("lineEdit")
  21.         self.pushButton = QtGui.QPushButton(self.centralwidget)
  22.         self.pushButton.setGeometry(QtCore.QRect(10, 50, 92, 28))
  23.         self.pushButton.setObjectName("pushButton")
  24.         self.pushButton_2 = QtGui.QPushButton(self.centralwidget)
  25.         self.pushButton_2.setGeometry(QtCore.QRect(120, 50, 92, 28))
  26.         self.pushButton_2.setObjectName("pushButton_2")
  27.         MainWindow.setCentralWidget(self.centralwidget)
  28.         self.menubar = QtGui.QMenuBar(MainWindow)
  29.         self.menubar.setGeometry(QtCore.QRect( 0,  0, 226, 25))
  30.         self.menubar.setObjectName("menubar")
  31.         MainWindow.setMenuBar(self.menubar)
  32.         self.statusbar = QtGui.QStatusBar(MainWindow)
  33.         self.statusbar.setObjectName("statusbar")
  34.         MainWindow.setStatusBar(self.statusbar)
  35.  
  36.         self.retranslateUi(MainWindow)
  37.         QtCore.QMetaObject.connectSlotsByName(MainWindow)
  38.  
  39.     def retranslateUi(self, MainWindow):
  40.         MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "ХабраОкно", None, QtGui.QApplication.UnicodeUTF8))
  41.         self.pushButton.setText(QtGui.QApplication.translate("MainWindow", "PushButton", None, QtGui.QApplication.UnicodeUTF8))
  42.         self.pushButton_2.setText(QtGui.QApplication.translate("MainWindow", "PushButton", None, QtGui.QApplication.UnicodeUTF8))
  43.  
  44.  
  45. if __name__ == "__main__":
  46.     import sys
  47.     app = QtGui.QApplication(sys.argv)
  48.     MainWindow = QtGui.QMainWindow()
  49.     ui = Ui_MainWindow()
  50.     ui.setupUi(MainWindow)
  51.     MainWindow.show()
  52.     sys.exit(app.exec_())
  53.  

    Во-первых, как мы видим, класс наследуется не от QMainWindow, а от object — это так называемая «новая» версия классов Python, при этом объект типа QMainWindow передается в метод класса как параметр. Это создает некоторую путаницу при работе с виджетами — объекты виджетов являются полями не класса окна, а родительского класса Ui_MainWindow. Но как с удобством, так и с неудобством этого, естественно, можно и поспорить. Тут уж каждому свое.
    Каждому объекту присваивается внутреннее имя, и это довольно любопытная вещь — нечто среднее между делфовскими свойствами Caption и Name. По сути, это имя требуется в том случае, когда к виджету не очень удобно обращаться как к полю класса. Если же у вас нет сложных генерируемых на лету форм и больших цепочек наследования — без этих имен можно спокойно обойтись, что я обычно и делаю. Кроме того, для создания интерфейса с поддержкой перевода на разные языки все текстовые данные прогоняются через транслятор и приводятся к кодировке UTF-8, причем это вынесено в отдельный метод класса. И все бы хорошо, только для каждого объекта копируется вот эта здоровенная строчка:
QtGui.QApplication.translate(«MainWindow», «ХабраОкно», None, QtGui.QApplication.UnicodeUTF8)

Почему бы не вынести ее в отдельный метод класса? :) Давайте в своем коде (который будем писать на основе сгенеренного файла) сделаем, например, так:
Copy Source | Copy HTML
  1. def toUtf(self, text):
  2.     return QtGui.QApplication.translate("MainWindow", text, None, QtGui.QApplication.UnicodeUTF8)

    Код не ухудшится с точки зрения читабельности, зато возвращаемые из сторонних функций строки будет легко преобразовывать к нужному типу.
    Кстати, то, что в генерируемом pyuic4 коде указывается полный адрес каждого модуля первого уровня — это в данном случае плюс, так как для разработки действительно полезно знать родителя для отдельного метода. Хотя баталии между любителями полных адресов и приверженцами строчек типа "from module import *" не утихают никогда.

Даешь прааактику!


    Чувствую, я уже надоел вам своей болтовней на отвлеченные темы, поэтому давайте рванем с места в карьер и разберем несколько типовых примеров, с которыми сталкиваются люди, изучающие PyQt4. Нет, я не буду здесь писать руководство для новичков, а просто опишу свой собственный опыт и подводные камни, с которыми пришлось столкнуться.
    Для начала давайте сделаем такую вещь — вынесем форму в отдельный модуль, который подключается к проекту. Из-за двойной классовой структуры, описанной выше, из функции создания окна придется возвращать два аргумента, а при создании главного окна — целых три. Итак, на повестке дня два файла — запускающий:
Copy Source | Copy HTML
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import sys
  4. from forms import MainForm
  5.  
  6. def main():
  7.     app, mainForm, window = MainForm.init()
  8.     window.show()
  9.     sys.exit(app.exec_())
  10.  
  11. if __name__ == "__main__":
  12.     main()

и файл, собственно, формы:
Copy Source | Copy HTML
  1. # -*- coding: utf-8 -*-
  2. import sys
  3. from PyQt4 import QtCore, QtGui, Qt
  4.  
  5. class mainWindow(object):
  6.     def setupUi(self, MainWindow):
  7.         # установим для окна фиксированный размер (знание метода лишним не будет)
  8.         MainWindow.setFixedSize(950, 550)
  9.         # я главный, а все виджеты от меня наследуются
  10.         self.main = QtGui.QWidget(MainWindow)
  11.         MainWindow.setCentralWidget(self.main)
  12.         # для полноты ощущений создадим меню "Файл"
  13.         self.menubar = QtGui.QMenuBar(MainWindow)
  14.         self.menubar.setGeometry(QtCore.QRect( 0,  0, 559, 25))
  15.         # создаем триггер-действие QAction, чтобы привязать его к пункту меню
  16.         self.menu_file_exit = QtGui.QAction(self.main)
  17.         self.menu_file_exit.setText(self.toUtf("&Выход"))
  18.         MainWindow.connect(self.menu_file_exit, QtCore.SIGNAL('triggered()'), sys.exit)
  19.         # создаем пункт меню и добавляем в него наш QAction
  20.         self.menu_file = self.menubar.addMenu(self.toUtf('&Файл'))
  21.         self.menu_file.addAction(self.menu_file_exit)
  22.         MainWindow.setMenuBar(self.menubar)
  23.         # для солидности приделываем статусбар
  24.         self.statusbar = QtGui.QStatusBar(MainWindow)
  25.         MainWindow.setStatusBar(self.statusbar)
  26.         # двигаем окно куда нам хочется
  27.         MainWindow.move(140, 80)
  28.         self.retranslateUi(MainWindow)
  29.  
  30.     def retranslateUi(self, MainWindow):
  31.         # даем окну название
  32.         MainWindow.setWindowTitle(self.toUtf("ХабраОкно 2.0"))
  33.  
  34.     def toUtf(self, text):
  35.         # та самая функция перевода
  36.         return QtGui.QApplication.translate("MainWindow", text, None, QtGui.QApplication.UnicodeUTF8)
  37.  
  38. def init():
  39.     # инициализируем Qt
  40.     app = QtGui.QApplication(sys.argv)
  41.     # создаем отдельный, независимый объект окна...
  42.     MainWindow = QtGui.QMainWindow()
  43.     # ...и прогоняем его через наш класс
  44.     form = mainWindow()
  45.     form.setupUi(MainWindow)
  46.     return app, form, MainWindow

    В данном случае проект имеет такую структуру:
main.py
forms/
>    __init__.py (пустой файл, нужен, чтобы папка распознавалась как Python-пакет)
>    MainForm.py

Я знаю, что такой способ разделения можно ругать и ругать, однако ж сколько полезного мы узнали о создании окна! :) А теперь давайте не будем останавливаться на достигнутом и создадим дочернее окно, чтобы нашему было не так одиноко (не зря же я создавал отдельный каталог forms). Более того, сделаем его модальным (родительское окно не будет реагировать на действия пользователя, пока открыто дочернее), дабы шаловливые ручки юзеров не привели к плохим последствиям. Для этого создадим в каталоге forms файл ChildForm.py, в котором опишем дочернюю форму:
Copy Source | Copy HTML
  1. # -*- coding: utf-8 -*-
  2. from PyQt4 import QtCore, QtGui
  3.  
  4. class childWindow(object):
  5.     def setupUi(self, SmallWindow):
  6.         SmallWindow.setFixedSize(330, 200)
  7.         SmallWindow.setWindowFlags(QtCore.Qt.Window)
  8.         self.retranslateUi(SmallWindow)
  9.         SmallWindow.setWindowModality(QtCore.Qt.WindowModal)
  10.  
  11.     def retranslateUi(self, Form):
  12.         Form.setWindowTitle(self.toUtf("Я - дочернее окно"))
  13.  
  14.     def toUtf(self, text):
  15.         return QtGui.QApplication.translate("SmallWindow", text, None, QtGui.QApplication.UnicodeUTF8)
  16.  
  17. def init(parentwindow):
  18.     SmallWindow = QtGui.QWidget(parentwindow)
  19.     form = childWindow()
  20.     form.setupUi(SmallWindow)
  21.     return form, SmallWindow

а также внесем некоторые изменения в файл основной формы:
Copy Source | Copy HTML
  1. ...
  2. from forms import ChildForm
  3. ...
  4. # создаем свой класс окна, это нужно, чтобы решить кое-какие проблемы с наследованием
  5. class myQMainWindow(QtGui.QMainWindow):
  6.     def __init__(self, parent=None):
  7.         QtGui.QMainWindow.__init__(self, parent)
  8. ...
  9. def setupUi(self, MainWindow):
  10.         ...
  11.         # выносим окно в поле класса для более удобного наследования
  12.         self.mainwindow = MainWindow
  13.         # рисуем кнопку, по которой будет отображаться дочернее окно
  14.         self.btnHello = QtGui.QPushButton(self.main)
  15.         self.btnHello.setGeometry(QtCore.QRect(20, 19, 92, 28))
  16.         MainWindow.connect(self.btnHello, QtCore.SIGNAL('clicked()'), self.showChildWindow)
  17.         ...
  18.  
  19. def retranslateUi(self, MainWindow):
  20.         ...
  21.         self.btnHello.setText(self.toUtf("Жми!"))
  22.         ...
  23.  
  24. def showChildWindow(self):
  25.         self.childForm, self.childWindow = ChildForm.init(self.mainwindow)
  26.         self.childWindow.show()
  27.  
  28. def init():
  29.     ...
  30.     #MainWindow = QtGui.QMainWindow()
  31.     MainWindow = myQMainWindow()
  32.     ...

    Вуаля! У нас есть родительское и дочернее окна.

Думаю, на сегодня посиделку завершим, но это только начало :) Я знаю, что этот топик содержит не так много полезной информации, как хотелось бы, но обещаю исправиться — на следующей посиделке будет сплошная практика.
И да, спасибу юзернейму poltergeist с форума python.su за кучу полезных советов!
Николай @enchantner
карма
157,5
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (28)

  • +11
    Этих разговоров уже) Вступительных топиков — уйма, а когда дальше идешь, тогда проблемы и начинаются. Вы бы лучше поведали про использование QGraphicsView или про то, как вы структурируете свои проекты(все слоты пишете в одном классе? :) ).
    • +4
      Продолжение будет, обещаю, я уже начал его писать :) Фиксирую типовые вещи, которые обычно хочется реализовать в приложениях и описываю, как их сделал я. И нет, естественно, я не пишу все слоты в одном классе, иначе смысла в вынесении форм в отдельный файл не было бы никакого)
      • –1
        Спасибо за отличную статью, очень ждём продолжения более детального ;)
  • –2
    Прекрасный старт!
    Поведайте, пожалуйста, о деталях и тонкостях написания истинно кроссплатформенных GUI applications или там неужели в дейсвтительности всё гладко и можно не задумываться о том, что мой код будет компиляться под маком или виндами;
    • +2
      Ну, в питоне нет понятия «компилиться» и это уже плюс :) а для работы всех примеров достаточно установить бинарный пакет с сайта PyQt4. Ну или можете поступить совсем по-гиковски и собрать из исходников Sip и PyQt, установив MinGW — компилятор на винду. Если вам интересно — могу рассказать об этом на следующей посиделке.
      • 0
        Хорошо ;-) я имел ввиду, конечно, запускаться и работать; Я имею ввиду следующее: стоит ли мне заботиться о нюансах или можно написать приложение дать ссылку на svn, из которого пользователи могут скачивать мой код, далее python main.py и всё, и это одинаково хорошо и корректно работает на известных платформах (ну или на тех, где установлен кит); или мне придётся таки делать ос-специфичные билды?; в теории проблем не должно быть, но хочется узнать у человека, который непосредственно разрабатывал, как это на практике?

        ну а трансляцию в промежуточный код *.pyc можно также назвать компиляцией, хотя корректность этого утверждения под сомнением;
        • +1
          В данном случае все, что требуется для работы простого оконного приложения — это интерпретатор питона и, собственно, PyQt4. Но приложение, написанное c использованием последних версий PyQt4, не всегда будет хорошо работать на более старых. В частности, сейчас стандартом де-факто является версия не ниже 4.5. Таким образом, можно поступить несколькими способами — например, в описании к программе давать ссылку на закачку нужной версии, собирать все в один инсталлятор (например, exe для винды, собранный чем-то потипу Inno Setup, или deb-пакет для систем наподобие Debian GNU/Linux или Ubuntu, в котором все зависимости определяются и устанавливаются автоматически), ну или использовать вещи потипу py2exe, даром что собранные им Qt-приложения отлично работают под виндой без всяких дополнительных телодвижений. В остальном нюансов для Qt практически нет, все зависит именно от программиста и переносимости написанного им Python-кода. Но, повторюсь, при установленных интерпретаторе и PyQt4 проблем ни на какой системе быть не должно.
      • +3
        Не надо, пожалуйста, лучше обещанную практику. Тот, кто не сможет поставить под винду питон+pyqt+qt, безнадежен, куда уж ему программировать то?
  • +5
    Неплохая статья, радует что код грамотно подсвечен и не слишком перегружен деталями.

    Высказывания в первой части спорны. В частности вы выступаете портив 3-4 лишних генерируемых строк, забывая о том, что сам по себе PyQt содержит десятки тысяч строк на python и C++, не говоря уж о самом Qt. Но в любом случае стремление к чистоте похвально:) Не надо лишь делать столь категоричных выводов о том, что pyuic4 плохо.

    По поводу того, зачем класс интерфейса наследуется от object:
    Стиль кода Qt и рекомендации по стилю для Python программ очень отличаются. Вы не можете полностью отказаться от питон-стиля (т.к. он используется стандартной библиотеке), а так же не можете отказаться от стиля Qt (иначе вы потеряете связь с интерфейсом).

    В серьезных программах единство кода является серьезной проблемой. Разделение кода формы и генерируемого кода для этой формы на разные классы и разные файлы позволяют изолировать визуальный Qt-код от кода программы и свести использование Qt-стиля к минимуму, сохраняя единство и целостность проекта.

    Единственный минус, который вижу в статье — отсутствие выводов. Здесь, возможно, уместно добавить области использования PyQt и наоборот те случаи, когда его использование не целесообразно.

    Впрочем, коли вы обозначили стиль как беседу, то это простительно, но все равно могло бы значительно улучшить полезность текста.
    • +1
      Спасибо за подробный отзыв, замечания учел, думаю, в следующих топиках еще вернусь к обсуждению данной темы :)
  • +1
    оффтоп не совсем в тему, а для общего кругозора: www.pyside.org, Википедия,
    PySide — привязка языка Python к инструментарию Qt, совместимая на уровне API с PyQt, но, в отличие от последней, доступная для свободного использования как в открытых, так и закрытых (чем чаще всего являются коммерческие) проектах, поскольку лицензирована по LGPL.
    • +1
      Да, точно, хотел упомянуть в конце, но забыл) Все никак руки не дойдут попробовать.
  • 0
    Я почему-то всегда встречаю такой код для навешивания обработчиков:

    MainWindow.connect(self.btnHello, QtCore.SIGNAL('clicked()'), self.showChildWindow)

    А сам использую такой код:

    self.cb_scale.currentIndexChanged.connect(self.cbScaleChange)

    По-моему второй способ проще, но как-будто нигде не используется?..
    • НЛО прилетело и опубликовало эту надпись здесь
      • –1
        this->
  • 0
    А прикручивал ui динамически. На знаю насколько это оправдано вообще в этом конкретном случае, но может быть весьма полезным для сложных приложений, где формы могут добавляться (ну типа 1С).

    И потом можно же использовать метод передачи формы с Qtscript в ответе сервера — может быть очень удобно.
  • НЛО прилетело и опубликовало эту надпись здесь
  • +2
    Сейчас пару строк со своей колокольни скажу:
    Потихоньку кодю на родном для Qt языке C++ и могу сказать, что все эти PyQt PySide и так далее не слишком подходят для серьезных проектов. Это все можно применять в мелких графических утилитках, но писать на PyQt или PyGTK нечто большое и объемное это неоправданное безумие. Так как на выходе получится прожорливый монстрик. Более того скажу, что освоение C++/Qt4 не многим сложнее Питона.
    Конечно мне возразят, что если писать на C++, то придется компилировать код под каждую платформу, а питонью программу можно просто запускать. Это да, но для серьезных проектов это не проблема. Также как и не проблема для маленьких проектов падение скорости даже в 1000 раз по сравнению с C++.
    А те, кому нужна расширяемость приложения за счет скриптов, могут обратить внимание на обычный javascript, за счет обьектной модели, его можно легко и очень глубоко интегрировать в свое Qt приложение.
    Но даже если этого мало, то скоро придет QML, который перевернёт все ваши представления о гуестроении. Фактически дни традиционных виджетов уже сочтены.
  • 0
    Согласен с предыдущими ораторами, что в большинстве случаев использование форм — скорее добро чем зло. Генерируемые файлы редактировать не надо, надо вызывать их setupUi из кода с логикой приложения.

    Я же возражу по поводу toUtf — вы как вообще приложение переводить потом собрались? Ведь делается это так: с использованием pylupdate4 сканируется код на предмет вызовов QtGui.QApplication.translate, параметры этих вызовов собираются в единую базу и переводятся в Qt Linguist.
    • 0
      Я с вами согласен, но неужели вы сто процентов приложений пишете с поддержкой многоязычности? И потом, именно для того и существует функция retranslateUI — необязательно ковыряться с лингвистом, просто в случае крайней необходимости можно сделать подгрузку языкового файла из внешнего плагина, а функция уже любые строки переварит. Но если писать что-то большое и серьезное (хотя меня выше уже начали убеждать, что это почти невозможно :) ) с поддержкой кучи языков — тогда я с вами полностью согласен.
      • +1
        кстати для интересующихся темой — нашел на микрохабре отличную статейку по переводу в Qt с примерами на C++. Кому понадобится — переписать на питон легко, ибо фактически все одно и то же.
      • 0
        Если вы не собираетесь писать локализуемое приложение, то тем более непонятно зачем делать метод toUtf, то возможно проще писать так, да и работать будет явно быстрее:
        MainWindow.setWindowTitle(QString.toUtf8("ХабраОкно 2.0"))

        Следующий вопрос — редактирование автосгенерированного файла — это неверный подход. pyuic4 как я вижу написан с таким же рассчетом, что и оригинальная утилита uic4 из Qt4 SDK, т.е. код генерируется таким образом чтобы максимально отделить бизнес логику приложения от графического интерфейса пользователя. Пример: вы захотите поменять две кнопки местами, что для этого делать? Если вы оставите файл как есть, то просто в ui форме поменяете две кнопки местами и снова сгенерируете код на питоне, логику приложения менять не придется. В вашем же случае нужно будет либо а) править код построения gui руками б) заново генерировать код из ui файла и опять же приводить его к нужному виду. А теперь представим ситуацию, что надо не просто переставить две кнопки, но и добавить еще пару причем с хитрым расположением Layout'ов… Как показывает практика ручное редактирование такого кода довольно дорогое удовольствие…

        PS извиняюсь за возможные ошибки синтаксиса — я пишу все таки не на питоне, а на c++ :)
        • 0
          ну я не то чтобы использую полностью ui-конвертированный код, я пишу на его основе свой (не без копипасты), однако ничего не мешает провести действия в дизайнере, опять сгенерить в кодовый файл одной командой и посмотреть, что необходимо изменить, это не так долго и неудобно, как может показаться.
          А насчет QString.toUtf8() — этот метод я сам нашел буквально через час после написания топика :) Спасибо за совет, попробую. Все попробую!)
          • 0
            Извиняюсь, там fromUtf8 :)
            что по поводу правок ручных — у меня в проекте некоторые файлы, сгенерированные на основе ui достигают в размере до полутора тысяч строк — думается такое руками править довольно сложно, не находите?
          • 0
            >ну я не то чтобы использую полностью ui-конвертированный код, я пишу на его основе свой (не без копипасты), однако ничего не мешает провести действия в дизайнере, опять сгенерить в кодовый файл одной командой и посмотреть, что необходимо изменить, это не так долго и неудобно, как может показаться.

            После тысячной правки у вас мнение поменяется на противоположное, к тому же ui файлы помогают лучшей кастомизации. Для обучения может и сгодится, но для чего-то серьезного только ui файлы.
        • 0
          Если вы не собираетесь писать локализуемое приложение, то тем более непонятно зачем делать метод toUtf, то возможно проще писать так, да и работать будет явно быстрее:
          MainWindow.setWindowTitle(QString.toUtf8("ХабраОкно 2.0"))


          А можно еще проще — MainWindow.setWindowTitle(u"ХабраОкно 2.0")

          PyQt отлично умеет мэппить unicode в QString :-)
          • 0
            PyQt-то умеет, но у такой программы, как ни странно, возникают проблемы при запуске под виндой. В частности, я столкнулся с тем, что виндовый питон начал ругаться на DecodeError после сборки программы с помощью py2exe.
  • 0
    Не очень понял, чем вам uic не угодил. Код, который он генерит не нужно изменять. Его даже читать не нужно, это код «оживляющий» xml-представление формы, которое создается в дизайнере.

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