Completely blind guessing here, since I'm not familiar with PyQt C++
side, but what if:
- Chimera::_py_enum_types contained mapping
not only to C++ name, but also type id
- Chimera::registerPyEnum the would insert
both items into the hash, generating type id using
qRegisterMetaType() (assuming that it's possible to get hold of
corresponding QMetaType instance here)
- The lookup inside Chimera::parse_py_type
would extract both name and value, and use assign "metatype =
QMetaType(metaTypeId)" instead of "QMetaType(QMetaType::Int)"
Alternatively, it's probably possible to not track int IDs, just do:
- QMetaType::registerType() in Chimera::registerPyEnum
- Use QMetaType::fromName(cpp_qualname) in Chimera::parse_py_type
Cheers,
Ivan
On 05/03/2024 17:49, Phil Thompson
wrote:
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