QUiLoader.createWidget equivalent in PyQt

2019-06-07 16:17发布

问题:

I have a PySide application that I'm investigating making compatible with PyQt4. Obviously this shouldn't be too difficult, but I'd like to minimise the number of code changes necessary. The biggest difference I've come across (which affects my program) is the fact that PyQt does not wrap the QUiLoader class.

Now I realise that I can still load ui files with the uic module in PyQt, however I'm currently using a subclass of QUiLoader in PySide that implements some custom functionality that I'd like to reserve if possible.

The functionality is as follows. I've subclassed QUiLoader and overridden the createWidget() method. My new implementation allows you to dynamically register widget promotions at application runtime. I can do this because the createWidget() method is responsible for instantiating the widgets from the ui file, after which (I believe) the standard QUiLoader implementation applies the specified properties from the ui file.

My Question is, is there a similar method I could override in PyQt to dynamically set widget Promotion at runtime, rather than having to set it statically through Qt Designer and the ui file.

P.S. I'm looking for a solution that involves minimal change to my existing code. For instance if I could replace my PySide QUiLoader subclass with a class that provides equivalent behaviour under PyQt, that would be ideal.

EDIT: The implementation would be used something like:

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

This is effectively what I have made with my subclass of QUiLoader in PySide. Any widget in the .ui file with the name "myWidgetNameInQtDesigner" would be instantiated as an instance of ClassToPromoteTo.

回答1:

This turns out to be quite easy, so long as you are willing to promote the relevant widgets in Qt Designer.

The idea is to add a dummy module to sys.modules and then dynamically modify the custom widget classes it contains.

So if the "Header file" was set to "mylib.dummy" when promoting widgets in Qt Designer, you would do something like this when loading ui files with 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()