Need help with custom enum properties in Qt6 Designer

Ivan Sinkarenko ivan.sinkarenko at cern.ch
Mon Mar 4 15:58:37 GMT 2024


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