[PySide] QtUiTools.QUiLoader crash with custom widget
Tyler W. Wilson
tyler at tylerlabs.com
Tue May 1 17:42:31 CEST 2012
On 5/1/2012 5:37 AM, Ludo Visser wrote:
> On Apr 30, 2012, at 5:16 pm, Tyler W. Wilson wrote:
>
>> Ditto on this issue for me. I just ran into this as well trying to add a
>> custom widget to a designer-based application. I had to move to PyQt4
>> temporarily to make it work.
>>
>> Thanks,
>> Tyler
>>
>> On 4/30/2012 9:58 AM, Stefan wrote:
>>> Hi,
>>>
>>> I'm trying to create a QMainWindow in the Designer and load the ui file
>>> dynamically with QUiLoader in pyside 1.1.0. When I don't register any
>>> custom types it works, but obviously fails to create my derived class.
>>> When I register them it crashes. Here's a small example that crash for
>>> me on windows running python 2.7 and pyside 1.1.0:
>>>
>>> from PySide import QtCore, QtGui, QtUiTools
>>> import sys
>>>
>>> class MyWidget(QtGui.QWidget):
>>> def __init__(self, parent=None):
>>> super(MyWidget, self).__init__(parent)
>>>
>>> if __name__ == '__main__':
>>> application = QtGui.QApplication(sys.argv)
>>>
>>> loader = QtUiTools.QUiLoader()
>>> loader.registerCustomWidget(MyWidget)
>>> print loader.availableWidgets()
>>> print loader.createWidget('QLabel')
>>> print loader.createWidget('MyWidget')
>>>
>>> Running this prints the following:
>>>
>>> [...]
>>>
>>> So it the class is in there, it manages to create a QLabel, but then it
>>> crashes.
>>>
>>> Any ideas why? I don't have any pdb for python, so it's hard to get a
>>> callstack.
>>>
>>> /Stefan
> I'm not sure what is causing the crash, but one way to obtain the functionality you require is to subclass the QUiLoader class to handle your custom widgets (see http://www.mail-archive.com/pyside@lists.openbossa.org/msg00878.html). For example something like this (here, a top-level widget is used to wrap around the ui-loaded widget, and this top-level widget has an attribute specifying which custom widgets it wants to load; of course, different approaches are possible):
>
> def createWidget(self, className, parent = None, name = ""):
> if className in QtUiTools.QUiLoader.availableWidgets(self):
> widget = QtUiTools.QUiLoader.createWidget(self, className, parent, name)
> else:
> if hasattr(self.baseinstance, "customWidgets"):
> if className in self.baseinstance.customWidgets.keys():
> widget = self.baseinstance.customWidgets[className](parent)
> else:
> raise KeyError("Unknown widget '%s'" % className)
> else:
> raise AttributeError("Trying to load custom widget '%s', but base instance '%s' does not specify custom widgets." % (className, repr(self.baseinstance)))
>
> if self.baseinstance is not None:
> setattr(self.baseinstance, name, widget)
>
> return widget
>
>
No doubt the issue might be worked around like shown above, but it seems
like the base UILoader ought to handle this transparently, especially
considering there is a section in .ui file that specifies the custom
widgets. Plus, it does work in PyQt4. For example, my .ui includes this:
<customwidgets>
<customwidget>
<class>QGradient</class>
<extends>QWidget</extends>
<header>QGradient</header>
<container>1</container>
</customwidget>
</customwidgets>
So I would expect the base UILoader to look at this section and perform
the proper imports to make these widgets available.
But thank you for the tip on the work-around.
- Tyler
More information about the PySide
mailing list