Веселуха начинается, когда возникает необходимость изменить ресурс. Путей при этом два: описания новых контролов ресурса добавлять в ранее сгенерированный код руками по образу и подобию существующих или понадеяться на корректную перегенерацию.
Оба пути не очень. Первый более безопасный (нет шансов потерять код прикладной логики) но медленный, трудоемкий и чреватый ошибками. На втором есть серьезная опасность потерять код, написанный руками, генератор-то о нем ничего не знает. Чтобы снизить вероятность повреждения кода прикладной логики, как правило, генераторы оборачивают свой код в специально обученные комментарии. Эти уродливые комменты бесят меня неимоверно и хожу я обычно по первому пути.
PyQt в этом отношении сильно радует. Код сгенерированного класса формы не предназначен для ручной правки, от него предлагается наследовать или агрегировать (слава великой концепции сигналов-слотов). Более того, в PyQt есть возможность динамически генерировать классы форм по ресурсу без создания промежуточного файла. Я был в восторге. Все вышеописанное позволяет написать компактную фабрику классов виджетов, требующую на входе имя файла ресурсов и классы, реализующие прикладную логику.
from PyQt4.uic import loadUiType
class CWidgetFactory(object):
u'''
Абстрактная фабрика классов виджетов PyQt
'''
@classmethod
def create(cls, fileName, slotHandleClasses=None):
u'''
Создает класс виджета PyQt.
fileName - имя файла ресурса ui
slotHandleClasses - итератор, возвращающий базовые классы, реализующие прикладную логику виджета.
Порядок разрешения методов (MRO) создаваемого класса - прикладные базовые классы,
в порядке выдачи итератором slotHandleClasses, базовый класс виджета Qt.
Такой MRO обеспечивает возможность переопределения виртуальных методов объектов Qt.
'''
uiClass, qtBaseClass = loadUiType(fileName)
base_classes = (tuple(slotHandleClasses) or ()) + (qtBaseClass,)
return type(str(fileName), base_classes, {u'uiClass':uiClass,
u'__init__':cls.__constructor,
u'slotHandleClasses':slotHandleClasses})
@staticmethod
def __constructor(self, parent=None, *args, **kwargs):
u'''
Конструктор класса виджета.
Обеспечивает необходимый порядок вызовов конструкторов базовых классов
и инициализирует интерфейс.
'''
self.__class__.__base__.__init__(self, parent)
self.ui = self.uiClass()
self.ui.setupUi(self)
if self.__class__.slotHandleClasses:
[base_cls.__init__(self, *args, **kwargs)
for base_cls
in self.__class__.slotHandleClasses]Использовать фабрику очень просто:
EntityDialog = CWidgetFactory.create('entity.ui', [EntityDialogHandler])
dlg = EntityDialog(parent)
dlg.exec_()Здесь, entity.ui - файл ресурса диалога, EntityDialogHandler - класс прикладной логики диалога, их может быть несколько.
Для упрощения создания главного окна и приложения PyQt есть еще один маленький класс:
from PyQt4.QtCore import QTranslator
from PyQt4.QtGui import QApplication
from wfactory import CWidgetFactory
class CommonApp(QApplication):
u'''
Обертка над классом приложения Qt. Автоматизирует создание главного окна приложения,
инициализирует локализацию приложения.
'''
def __init__(self, args, ui_file, trans_file=None, handles=None, maximize=True):
u'''
args - список внешних аргументов, как правило, sys.argv
ui_file - ресурс главного окна
trans_file - файл локализации
handles - итератор прикладных базовых классов
maximize - признак максимизации главного окна при старте приложения.
'''
QApplication.__init__(self, args)
if trans_file:
self.translator = QTranslator(self)
self.translator.load(trans_file)
self.installTranslator(self.translator)
self.main_wnd = CWidgetFactory.create(ui_file, handles)()
self.setActiveWindow(self.main_wnd)
if maximize:
self.main_wnd.showMaximized()
else:
self.main_wnd.show()Использовать так:
import sys
from wfactory import CommonApp
from mainwnd import MainWndHandler
if __name__ == u'__main__':
app = CommonApp(sys.argv, u'main.ui', None, [MainWndHandler])
app.exec_()P.S. Разговор выше шел об оконных ресурсах формата ui. В Qt (и PyQt) есть еще один вид ресурсов (он так и называется - ресурсы :), содержащий, как правило, графику и также требующий генерации кода - qrc. Вот для этих ресурсов не предусмотрена динамическая генерация объектов языка, видимо в связи с особенностями реализации, их приходится генерировать вручную. А очень жаль.
Комментариев нет:
Отправить комментарий