Веселуха начинается, когда возникает необходимость изменить ресурс. Путей при этом два: описания новых контролов ресурса добавлять в ранее сгенерированный код руками по образу и подобию существующих или понадеяться на корректную перегенерацию.
Оба пути не очень. Первый более безопасный (нет шансов потерять код прикладной логики) но медленный, трудоемкий и чреватый ошибками. На втором есть серьезная опасность потерять код, написанный руками, генератор-то о нем ничего не знает. Чтобы снизить вероятность повреждения кода прикладной логики, как правило, генераторы оборачивают свой код в специально обученные комментарии. Эти уродливые комменты бесят меня неимоверно и хожу я обычно по первому пути.
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. Вот для этих ресурсов не предусмотрена динамическая генерация объектов языка, видимо в связи с особенностями реализации, их приходится генерировать вручную. А очень жаль.
Комментариев нет:
Отправить комментарий