Эквивалент QUiLoader.createWidget в PyQt

У меня есть приложение PySide, которое я пытаюсь сделать совместимым с PyQt4. Очевидно, это не должно быть слишком сложно, но я хотел бы свести к минимуму количество необходимых изменений кода. Самая большая разница, с которой я столкнулся (которая влияет на мою программу), заключается в том, что PyQt не обертывает класс QUiLoader.

Теперь я понимаю, что я все еще могу загружать файлы пользовательского интерфейса с модулем uic в PyQt, однако в настоящее время я использую подкласс QUiLoader в PySide, который реализует некоторые пользовательские функции, которые я хотел бы зарезервировать, если это возможно.

Функционал следующий. Я создал подкласс QUiLoader и переопределил метод createWidget(). Моя новая реализация позволяет динамически регистрировать продвижение виджета во время выполнения приложения. Я могу это сделать, потому что метод createWidget() отвечает за создание экземпляров виджетов из ui-файла, после чего (я полагаю) стандартная реализация QUiLoader применяет указанные свойства из ui-файла.

Мой вопрос: есть ли аналогичный метод, который я мог бы переопределить в PyQt для динамической установки продвижения виджета во время выполнения, вместо того, чтобы устанавливать его статически через Qt Designer и файл пользовательского интерфейса.

P.S. Я ищу решение, которое требует минимальных изменений в моем существующем коде. Например, если бы я мог заменить свой подкласс PySide QUiLoader классом, который обеспечивает эквивалентное поведение в PyQt, это было бы идеально.

EDIT: Реализация будет использоваться примерно так:

loader = UiLoader()
loader.registerCustomPromotion("myWidgetNameInQtDesigner",ClassToPromoteTo)
ui = loader.load('myUiFile.ui')

Фактически это то, что я сделал с моим подклассом QUiLoader в PySide. Любой виджет в файле .ui с именем "myWidgetNameInQtDesigner" будет создан как экземпляр ClassToPromoteTo.


person three_pineapples    schedule 09.01.2014    source источник
comment
Взгляните на этот stackoverflow.com/a/14894550/674475 .   -  person Fenikso    schedule 09.01.2014
comment
Есть код, который делает это наоборот, например. PyQT > PySide здесь. Может быть, вы найдете это полезным.   -  person Fenikso    schedule 09.01.2014
comment
@Fenikso Подобный код PySide вдохновил меня на написание собственного подкласса QUiLoader в PySide, который допускает динамическое продвижение. Я, вероятно, должен был быть чист, что он позволяет динамически продвигать любой виджет в вашем файле пользовательского интерфейса в ваш собственный подкласс этого виджета. Код PyQt, с которым вы меня связали, позволяет это только для виджета верхнего уровня без родителя (насколько я вижу).   -  person three_pineapples    schedule 10.01.2014
comment
@three_pineapples. Вам действительно нужно динамически продвигать любой виджет? Каков вариант использования для этого? И вообще, как вы используете динамическое продвижение во время выполнения? Было бы полезно, если бы вы могли привести базовый рабочий пример, иллюстрирующий минимальную функциональность, которая вам действительно нужна.   -  person ekhumoro    schedule 10.01.2014
comment
@ekhumoro Я динамически продвигаю виджеты в своем коде. Могу ли я переписать свой код, чтобы мне не нужно было? Возможно, но это будет изрядная часть работы, которой я хотел бы избежать. Насколько я понимаю, мне пришлось бы создавать экземпляры пользовательских виджетов в коде Python, применять любые свойства, которые я установил для базового виджета в Qt Designer, удалять базовый экземпляр из файла пользовательского интерфейса, а затем добавлять экземпляр пользовательского виджета. к любому макету/виджету, которому он был назначен в Qt Designer. Опять же, очевидно, что это возможно, но я лучше попытаюсь сохранить свою текущую архитектуру, если смогу.   -  person three_pineapples    schedule 10.01.2014
comment
@three_pineapples. Чего я не понимаю, так это почему вы не можете продвигать виджеты в Qt Designer. Это кажется необоснованным условием.   -  person ekhumoro    schedule 10.01.2014
comment
@ekhumoro Представьте себе, что 90% двух пользовательских интерфейсов (или их частей) являются общими. При динамическом продвижении во время выполнения вам нужен только один файл пользовательского интерфейса, и вы можете изменить эти 10% во время выполнения. Если вы хотите внести общие изменения в эти две (части) пользовательских интерфейса, вам нужно отредактировать только один файл. Если вы хотите настроить свойство базового класса для обоих экземпляров, вы можете сделать это через файл ui. Вы также можете продвигать виджеты с помощью дизайнера Qt (эта функциональность имеет свой вариант использования), но продвижение виджетов в дизайнере Qt означает, что два экземпляра пользовательского интерфейса будут идентичными.   -  person three_pineapples    schedule 10.01.2014
comment
@ekhumoro, насколько мне известно, вы не можете продвигать виджет в дизайнере Qt, чтобы при первой загрузке он использовал пользовательский виджет x, а при второй загрузке - пользовательский виджет y. Похоже, что такая информация должна предоставляться во время загрузки файла пользовательского интерфейса в python, а не раньше.   -  person three_pineapples    schedule 10.01.2014
comment
@three_pineapples. Что ж, это еще предстоит выяснить. Кто знает, какой хакерство возможно...   -  person ekhumoro    schedule 10.01.2014


Ответы (1)


Это оказывается довольно просто, если вы готовы продвигать соответствующие виджеты в Qt Designer.

Идея состоит в том, чтобы добавить фиктивный модуль в sys.modules, а затем динамически изменить содержащиеся в нем пользовательские классы виджетов.

Итак, если для «Файла заголовка» было установлено значение «mylib.dummy» при продвижении виджетов в Qt Designer, вы должны сделать что-то подобное при загрузке файлов пользовательского интерфейса с помощью PyQt:

from types import ModuleType

# dummy module
module = sys.modules['mylib.dummy'] = ModuleType('dummy')

if mode == 'FOO':
    module.TextEdit = FooTextEdit
    module.LineEdit = FooLineEdit
    module.PushButton = FooPushButton
elif mode == 'BAR':
    module.TextEdit = BarTextEdit
    module.LineEdit = BarLineEdit
    module.PushButton = BarPushButton
else:
    module.TextEdit = QTextEdit
    module.LineEdit = QLineEdit
    module.PushButton = QPushButton

# loadUi/loadUiType will add the following import line:
# from mylib.dummy import TextEdit, LineEdit, PushButton
WidgetUI = uic.loadUiType('mywidget.ui'))[0]
ui = WidgetUI()
person ekhumoro    schedule 10.01.2014
comment
Спасибо, думаю, так и будет. Моя реализация PySide сделала это без какого-либо продвижения в Qt Designer (что полезно для таких виджетов, как QMainWindow, которые нельзя продвигать в QtDesigner), но я думаю, что единственный способ сделать это в PyQt — разветвить модуль PyQt4.uic и изменить это поведение (которое я особо не хочу делать!). К сожалению, я не могу заставить его работать, когда модуль называется mylib.dummy, но он работает, когда он называется mylib (uic вызывает ошибку импорта). Любые идеи (не то, чтобы это ужасно важно)? - person three_pineapples; 12.01.2014
comment
@three_pineapples. Я протестировал свое решение со структурой пакета, эквивалентной приведенной выше, и импорт у меня работал нормально. Структура была простой: main.py, lib/__init__.py, lib/app.py и lib/classes.py. Что касается разветвления uic: я полностью понимаю, почему вы хотели бы избежать этого - кошмар обслуживания, если он когда-либо был! - person ekhumoro; 12.01.2014
comment
Ах я вижу. Если вы используете mylib.dummy, вам действительно нужна структура файлов/папок для модуля mylib. Если у вас есть только «mylib», вы можете обойтись без создания каких-либо файлов. Ваше здоровье! - person three_pineapples; 12.01.2014