Найти - Пользователи
Полная версия: Делимся опытом использования QtDesigner + pyuic5
Начало » GUI » Делимся опытом использования QtDesigner + pyuic5
1 2 3 4 5
Metallikus
Привет, python.su
Есть необходимость срочно начать писать ГУЁвые программки под линь. После недолгого лурканья был выбран python (благо Лутца я почитал, а два тома даже прикупил). Ещё после некоторого времени лурканья для, собсно, ГУЯ была выбрана PyQt (tkinter уныл, а питоновская обвязка для gtk повергла меня в первобытный ужас). И вот здесь я столкнулся с острым недостатком информации. Современная реальность такова, что наиболее предпочтительной для освоения является связка python3 + Qt5. В то же время, практически все гайды описывают Qt4. Но не суть, методом тыка научился читать гайд про Qt4 и писать ГУЙ на Qt5, отличия минимальны. Суть в другом: все гайды по PyQt повествуют о написании ГУЯ самостоятельно. Под всеми этими гайдами есть комментарии, в которых говориться что писать ГУЙ руками не модно. Мол, в комплекте с Qt идёт замечательный WYSIWYG редактор QtDesigner, формирующий .ui файл на выходе. Сам же .ui файл можно конвертировать в .py при помощи утилиты pyuic. И вот здесь у нуба возникает проблема: получаемый .py имеет совершенно отличную структуру от написанных руками примеров из гайдов. Прошу поделиться опытом гуру, использующих данные инструменты. Как вы организуете свои питоновские проекты?
Сам я пришёл вот к какой схеме:
Файлы в проекте располагаются так:
./Designs - папка, содержащая файлы .ui и сконвертированные из них .py
./Forms - см примечание*
./main.py - вызывает основное окно
./ - содержит также разные скрипты типа progname.desktop configure.py, install.sh и т.п. См**
*Сконвертированные .py не трогаю, ибо при перерисовке и переконвертации потеряется весь набранный руками код. Значит, для каждого сконвертированного .py нужен написанный руками .py, с классом-наследником, переопределяющим всё необходимое. Если моя схема имеет право на существование, наверно пихну их в папку ./Forms Пока же они лежат прямо в ./
** ./ - корневой каталок проекта.

Как реализую сами окошки
Сконвертированный .py содержит вот какой класс:
class Ui_MainWindow(object):
     def setupUi(self, MainWindow):
          #код, преобразующий переданное MainWindow
     def retranslateUi(self, MainWindow):
          #код, создающий русские надписи

Как видно, окно данный код не создаёт. Он даже не от QtWidgets.QMainWindow наследуется! Не то, что код из гайдов. Что ж, создавать окна будет обёртка. Для главного окна это будет ./main.py:
#Разные важные import
from Designes.form1 import Ui_MainWindow
class mainForm(Ui_MainWindow):
#Инициализация
     def __init__(self):
         Ui_MainWindow.__init__(self)
         self.window = QtWidgets.QMainWindow() #окно, которое должно быть передано 
         self.setupUi(self.window) #этой функции и преображено ей
         self.sett.clicked.connect(self.sett_onClick) #назначаем свои обработчики событий элементам
#..................
        self.window.show()
     def sett_onClick(self):
          #код обработки события клика по кнопке "настройки"
#...................
if __name__ == "__main__":
     app = QtWidgets.QApplication(sys.argv)
     form = maneForm()
     sys.exit(app.exec_())

Этот способ то, к чему пришёл я. Но я нуб, и потому ищу друзей совета. Насколько такой метод применим? Какие ещё ест способы?
Alen
Metallikus
Современная реальность такова, что наиболее предпочтительной для освоения является связка python3 + Qt5.

Python2.7 по прежнему по умолчанию во всех дистрибутивам, как и Qt4.

Metallikus
Суть в другом: все гайды по PyQt повествуют о написании ГУЯ самостоятельно. Под всеми этими гайдами есть комментарии, в которых говориться что писать ГУЙ руками не модно. Мол, в комплекте с Qt идёт замечательный WYSIWYG редактор QtDesigner, формирующий .ui файл на выходе. Сам же .ui файл можно конвертировать в .py при помощи утилиты pyuic. И вот здесь у нуба возникает проблема: получаемый .py имеет совершенно отличную структуру от написанных руками примеров из гайдов.

Не знаю, чего не модного в написание GUI руками, просто небольшая практика нужна. QtDisigner конечно хорош, но много лишнего, названия переменных кривые какие-то, наследования нет вообще, но на первое время пойдет.

Metallikus
Как вы организуете свои питоновские проекты?

Зависит, наверное от проекта, в проекте могут быть несколько приложений, и далеко не все на PyQt, например может быть серверная часть несущая функции, скажем, загрузки файлов или почтовой рассылки или еще чего-то. Некоторые части GUI-приложений, вполне себе могут содержать webkit-приложения, как часть Qt и соответсвенно html-файлы для шаблонизатора, к примеру jinja2 и статику вида js,css,images. Вполне может быть движок отчетов и соответсвенно отдельные функции для экспорта данных из базы данных и заполнения ими xlsx и pdf. Может быть движок с хитрыми вычислениями на базе numpy, может быть обширная сетевая обработка. Каждый проект уникален и его структура уникальна.
Metallikus
Alen, спасибо за ответ. Я так понял, резюме можно вывести следующее:
1) python3 и Qt4 вполне можно использовать
2) QtDesigner неполноценен и предназначен для новичков
3) проект можно организовать как угодно
Вот какие мысли это вызывает у меня:
1) Это понятно, но при выборе инструментов для освоения, упор лучше делать на перспективность. Qt3 тоже некоторое время использовалась параллельно с Qt4, значит и Qt5 полностью заменит Qt4 в своё время.
2) Наслеlование от object и правда наибольшая проблема, в гайдах-то всё совершенно по-другому реализуют. Может и стоит плюнуть на QtDesigner, что сократит количество модулей в проекте практически вдвое?.. Мало ли что там в каментах на хабре пишут
3) Я имел в виду как получше организовать ГУИ и логику его контролов. То есть именно организацию модулей одного приложения, возможно и многооконного.
py.user.next
Metallikus
Сконвертированный .py содержит вот какой класс:
Metallikus
class Ui_MainWindow(object):
Первое, что бросается в глаза - это слово object там, где оно не нужно. Да, для третьего питона генерятся такие вот файлы. Зачем этот мусор в третьем питоне?

Metallikus
class Ui_MainWindow:
Вот так должно быть.

Дальше связи сигналов со слотами - аналогично, используется стиль для Qt3. Оттуда длиннющие строки (а pep8 они - создатели конвертера - не соблюдают).
Дальше никакие имена, оно и понятно, это всё потом надо менять.

И, самое главное, все эти визивиги при любом изменении всё меняют обратно.

Так что для изучения того, как что-то построить, - можно заюзать, но для создания чистого и красивого проекта - нет.
Metallikus
Ок, всё понял. Настоящие профи пишут код для GUI руками. Вот почему про QtDesigner только каменты и есть, ни одного гайда.

py.user.next
Дальше связи сигналов со слотами - аналогично, используется стиль для Qt3. Оттуда длиннющие строки (а pep8 они - создатели конвертера - не соблюдают).
Э.. А у меня генериться примерно так:
self.btnExit.clicked.connect(MainWindow.close)
А как должно быть-то?
py.user.next
Metallikus
А у меня генериться примерно так:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>QMainWindow</string>
</property>
<property name="statusTip">
<string/>
</property>
<widget class="QWidget" name="centralwidget">
<property name="statusTip">
<string/>
</property>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="statusTip">
<string extracomment="0"/>
</property>
<property name="accessibleDescription">
<string/>
</property>
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="action_Exit"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="action_Exit">
<property name="text">
<string>Exit</string>
</property>
<property name="statusTip">
<string>exit?</string>
</property>
</action>
</widget>
<resources/>
<connections>
<connection>
<sender>action_Exit</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
</connections>
</ui>

[guest@localhost mainwindow]$ pyuic4 mainwindow.ui
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'mainwindow.ui'
#
# Created: Thu Nov 27 20:00:20 2014
# by: PyQt4 UI code generator 4.10.2
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s

try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.setEnabled(True)
MainWindow.resize(800, 600)
MainWindow.setStatusTip(_fromUtf8(""))
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setStatusTip(_fromUtf8(""))
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName(_fromUtf8("menubar"))
self.menuFile = QtGui.QMenu(self.menubar)
self.menuFile.setStatusTip(_fromUtf8(""))
self.menuFile.setAccessibleDescription(_fromUtf8(""))
self.menuFile.setObjectName(_fromUtf8("menuFile"))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
self.action_Exit = QtGui.QAction(MainWindow)
self.action_Exit.setObjectName(_fromUtf8("action_Exit"))
self.menuFile.addAction(self.action_Exit)
self.menubar.addAction(self.menuFile.menuAction())

self.retranslateUi(MainWindow)
QtCore.QObject.connect(self.action_Exit, QtCore.SIGNAL(_fromUtf8("triggered()")), MainWindow.close)
QtCore.QMetaObject.connectSlotsByName(MainWindow)

def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "QMainWindow", None))
self.menuFile.setTitle(_translate("MainWindow", "&File", None))
self.action_Exit.setText(_translate("MainWindow", "Exit", None))
self.action_Exit.setStatusTip(_translate("MainWindow", "exit?", None))

[guest@localhost mainwindow]$

Даже если переделать сигналы, всё равно там всё слитно, код не читаемый абсолютно.
Metallikus
QtCore.QObject.connect(self.action_Exit, QtCore.SIGNAL(_fromUtf8("triggered()")), MainWindow.close)
Кошмар какой. В pyuic5 такого уже нет.
Rodegast
> Под всеми этими гайдами есть комментарии, в которых говориться что писать ГУЙ руками не модно.
Модно, не модно это всё аргументы для блондинок. При написании программ нужно руководствоваться эффективностью, так вот “писать ГУЙ руками” НЕ ЭФФЕКТИВНО!

> Современная реальность такова, что наиболее предпочтительной для освоения является связка python3 + Qt5.
Использовать Qt5 ещё рано, хотя бы потому что он есть не во всех дистрибутивах (в стабильном Debian-е его точно нет).

> Наслеlование от object и правда наибольшая проблема
Нет здесь никакой проблемы.

> Первое, что бросается в глаза - это слово object там, где оно не нужно. Да, для третьего питона генерятся такие вот файлы.
Эти файлы генерятся для второго питона.

> Дальше связи сигналов со слотами - аналогично, используется стиль для Qt3. Оттуда длиннющие строки (а pep8 они - создатели конвертера - не соблюдают).
Ну и что?

> Дальше никакие имена, оно и понятно, это всё потом надо менять.
Что значит “никакие имена”

> И, самое главное, все эти визивиги при любом изменении всё меняют обратно.
Зачем вам что-то менять руками?
py.user.next
Rodegast
Эти файлы генерятся для второго питона.
И что дальше? Применяется-то это в третьем. А зачем в третьем object?

Rodegast
Ну и что?
Устаревший стиль.

Rodegast
Что значит “никакие имена”
Никакие - нечитаемые. То есть, если сделать побольше и подетальнее форму, то её даже понять будет невозможно.

Rodegast
Зачем вам что-то менять руками?
Во-первых, чтобы красиво смотрелось; во-вторых, чтобы не было ничего лишнего.


Rodegast
так вот “писать ГУЙ руками” НЕ ЭФФЕКТИВНО!
Да, проще скачать уже готовую программу. Визивиги всегда были фигнёй во всех областях. Они для блондинок, у которых знаний нет.
Metallikus
Rodegast
Нет здесь никакой проблемы.
При чтении гайдов есть. См. выше.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB