From pykde Tue Mar 05 16:49:59 2024 From: Phil Thompson Date: Tue, 05 Mar 2024 16:49:59 +0000 To: pykde Subject: Re: Need help with custom enum properties in Qt6 Designer Message-Id: <4dd7c10738dcf84e5e30a406d29424d5 () riverbankcomputing ! com> X-MARC-Message: https://marc.info/?l=pykde&m=170965728907042 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