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