Need help with custom enum properties in Qt6 Designer
Phil Thompson
phil at riverbankcomputing.com
Tue Mar 5 16:49:59 GMT 2024
The problem is 4. For Qt6 PyQt has to use qMetaTypeId() to register the
Qt enums. This is done statically with inline calls. As it's template
based I don't know how to do the equivalent for dynamically created
Python enums. I suspect that this is the missing step.
Phil
On 04/03/2024 15:58, Ivan Sinkarenko wrote:
> Hi Phil,
>
> Thanks for the info. Do you think this could be addressed in future
> releases? My project has a frequent use of designer plugins that have
> custom enum properties, so I would be interested to solve it.
> Potentially I could give you some assistance?
>
> I've tried to investigate the flow myself a bit, here's what I found:
>
> 1. When setting a new value, QMetaProperty::write() is called
> 2. It recognizes that it receives a new int value, and tries to
> convert it to the target type
> 3. Target type is derived from a meta type, referenced by the meta
> property, through a call "QMetaType
> t(mobj->d.metaTypes[data.index(mobj)]);"
> 4. This target type for some reason has ID = 0 (i.e. UnknownType, as
> defined by QMetaType::Type)
> 5. Conversion fails early, rejecting UnknownType, chained through
> QMetaProperty::write() -> QVariant::convert() ->
> QMetaType::canConvert()
> 6. QMetaProperty::write() returns early.
>
> Thanks,
> Ivan
>
> On 01/03/2024 18:50, Phil Thompson wrote:
>> On 01/03/2024 17:24, Ivan Sinkarenko wrote:
>>> Hi everybody,
>>>
>>> I've seen there's been a lot happening with enums in PyQt6,
>>> and I've managed to adapt to most of the problems, except one.
>>> I cannot figure out how to make custom enums work in custom widgets
>>> that are exposed to Qt Designer.
>>>
>>> This is my simplified code:
>>>
>>> ----------------------------------------------------------------------
>>> import enum
>>> from PyQt6 import QtDesigner, QtGui, QtWidgets, QtCore
>>>
>>> class MyWidget(QtWidgets.QWidget):
>>>
>>> @QtCore.pyqtEnum
>>> class MyEnum(enum.IntEnum):
>>> ONE = enum.auto()
>>> TWO = enum.auto()
>>>
>>> def __init__(self, *args, **kwargs) -> None:
>>> super().__init__(*args, **kwargs)
>>> self._prop = MyWidget.MyEnum.TWO
>>>
>>> @QtCore.pyqtProperty(MyEnum)
>>> def prop(self):
>>> print(f'Getting property val {self._prop}')
>>> return self._prop
>>>
>>> @prop.setter
>>> def prop(self, new_val):
>>> print(f'Setting new property val {new_val}')
>>> self._prop = new_val
>>>
>>> class Plugin(QtDesigner.QPyDesignerCustomWidgetPlugin):
>>>
>>> def name(self):
>>> return "MyWidget"
>>>
>>> def group(self):
>>> return "Buttons"
>>>
>>> def isContainer(self):
>>> return False
>>>
>>> def createWidget(self, parent):
>>> return MyWidget(parent)
>>>
>>> def icon(self):
>>> return QtGui.QIcon()
>>>
>>> def toolTip(self):
>>> return ""
>>>
>>> def whatsThis(self):
>>> return ""
>>>
>>> def includeFile(self):
>>> return "pyqt6_enum_designer_poc_plugin"
>>> ----------------------------------------------------------------------
>>>
>>> I want an enum property to be displayed in the PropertySheet.
>>> It's correctly represented by a combobox showing ONE and TWO as
>>> available options.
>>>
>>> TWO is correctly selected by default. However, when in Property sheet
>>> I try to set it to ONE,
>>> as soon as I click away from there, it's reset back to TWO. In fact,
>>> the setter does not get called,
>>> since the message inside is never printed. (Getter message is being
>>> printed).
>>>
>>> Properties do work without issues, if they have built-in types, such
>>> as QColor,
>>> or even native enums, such as Qt.Orientation.
>>>
>>> To try this code, you can save this code to
>>> "pyqt6_enum_designer_poc_plugin.py" and run like so:
>>> PYQTDESIGNERPATH=$(pwd) designer
>>>
>>> I use Qt Designer 6.6.2 and:
>>> - PyQt6 6.6.1
>>> - PyQt6-Qt6 6.6.2
>>> - PyQt6-sip 13.6.0
>>>
>>> (Also tried with PyQt6-6.5.3 PyQt6-Qt6-6.5.3, same result)
>>>
>>> There used to be a way to make this work in PyQt5, but in PyQt6 I
>>> tried multiple approaches without luck.
>>> If anybody knows the correct path, that would be very appreciated!
>>>
>>> Thanks,
>>> Ivan
>>
>> This is ringing a faint bell. I looked at it a long time ago and found
>> that Designer was just not making the normal call to write the changed
>> property value, maybe due to some sort of "optimisation". There may be
>> something wrong in the way that PyQt creates the QMetaObject for the
>> Python class but I never managed to get to the bottom of it.
>>
>> Sorry for not being more helpful.
>>
>> Phil
More information about the PyQt
mailing list