Qt Designer: Display a List of Enum Options in Custom Widget Properties Editor Using Python
-
I'm working on creating a custom widget for Qt Designer in Python using PyQt or PySide. I want to expose an enum property in the Qt Designer property editor, so that users can select from a list of predefined options rather than typing in arbitrary values.
In C++, it is possible to expose an enum to Qt Designer using Q_ENUMS and Q_PROPERTY, as described in this Stack Overflow question.
I want to achieve the same result in Python. Specifically, I want to:
- Define an enum in Python that can be used as a property in my custom widget.
- Ensure that this enum is displayed as a dropdown list in the Qt Designer property editor.
Here's an outline of what I have so far:
from qtpy.QtCore import Qt, QEasingCurve, QPropertyAnimation, QSize, Property, QPoint, QEnum from qtpy.QtWidgets import QCheckBox, QApplication, QLabel from enum import Enum class EasingCurveEnum(Enum): Option1 = 0 Option2 = 1 Option3 = 2 class QCustomCheckBox(QCheckBox): def __init__(self, parent=None): super().__init__(parent) self._easing_curve = EasingCurveEnum.Option1 # ... @Property(EasingCurveEnum, designable=True) def animationEasingCurve(self): return self._easing_curve @animationEasingCurve.setter def animationEasingCurve(self, curve): self._easing_curve = curveHow can I make the EasingCurveEnum property appear as a list of options in the Qt Designer property editor?
I've successfully registered my custom widget in Qt Designer, but the enum list property is not appearing.
Any guidance or examples would be greatly appreciated!
Thanks in advance!
If solution found, please share it here Stackoverflow post
-
Coming back (after 2 years ! ) to close this out, since I finally have a solution that's held up in production.
Short answer: you can't get a real inline dropdown in Designer's Property Editor from pure Python. That specific bit needs a compiled C++ plugin. But there's a Python path that works well in practice — I'll explain both.
What doesn't work (so you can skip the dead-ends I hit):
I tried a
QDesignerPropertySheetExtensionto swap the property's editor. On PySide6 6.11:- You can't delegate to Designer's built-in sheet —
extensionManager().extension(...)hands it back as a bareQObjectand shiboken can't recover the real interface, so the methods just aren't there. - Replacing the sheet wholesale with a Python-built one segfaults Designer during form load — even when every property returns a plain string. Its core assumes the internal C++ sheet.
Also worth knowing: declaring the property as a
Q_ENUM/@QEnumdoes give you a dropdown, but only for static, compile-time enums baked into the widget. It's no help if your options are computed at runtime (mine come from a project file), which was the whole point.What actually works — a task-menu extension:
Right-click the widget → your action pops a combo box → you write the choice back through the form cursor. It's undo-aware, dirties the form, and saves to the
.uilike any normal edit.from PySide6.QtDesigner import (QExtensionFactory, QPyDesignerTaskMenuExtension, QDesignerFormWindowInterface) from PySide6.QtGui import QAction from PySide6.QtWidgets import QInputDialog TASKMENU_IID = "org.qt-project.Qt.Designer.TaskMenu" class ThemeTaskMenu(QPyDesignerTaskMenuExtension): def __init__(self, widget, parent=None): super().__init__(parent) self._widget = widget self._action = QAction("Set theme…", self) self._action.triggered.connect(self._choose) def taskActions(self): return [self._action] def _choose(self): names = ["Light", "Dark", "Solarized"] # build this list at runtime current = self._widget.property("appTheme") or "" i = names.index(current) if current in names else 0 name, ok = QInputDialog.getItem(self._widget.window(), "Theme", "Theme:", names, i, False) if not ok or not name: return fw = QDesignerFormWindowInterface.findFormWindow(self._widget) # cursor path = undoable + saved to the .ui; a raw setProperty won't stick (fw.cursor().setWidgetProperty(self._widget, "appTheme", name) if fw else self._widget.setProperty("appTheme", name)) class ThemeTaskMenuFactory(QExtensionFactory): def createExtension(self, obj, iid, parent): if iid != TASKMENU_IID or not isinstance(obj, MyCustomWidget): return None return ThemeTaskMenu(obj, parent)Register it in your plugin's
initialize(core):core.extensionManager().registerExtensions( ThemeTaskMenuFactory(core.extensionManager()), TASKMENU_IID)Two things that bit me:
- Apply via
fw.cursor().setWidgetProperty(...), not justwidget.setProperty(...)— otherwise the change never makes it into the saved.ui. - Keep the underlying property a plain, validated
@Property(str). The menu is only an input aid; the stored value stays portable and works fine on machines without your plugin. - If you have both PyQt5 and PySide6 installed, launch designer with
QT_API=pyside6or qtpy may pick PyQt5 and your plugin import will fail.
So: static enum →
Q_ENUM. Runtime options → task-menu extension. True inline dropdown → C++ only.I use a slightly fancier version of this (a little dock with a combo per property) in my widgets library if anyone wants a fuller reference:
https://github.com/SpinnCompany/QT-PyQt-PySide-Custom-WidgetsMarking this solved — hope it saves someone the segfault hunt.
- You can't delegate to Designer's built-in sheet —
-
I'm working on creating a custom widget for Qt Designer in Python using PyQt or PySide. I want to expose an enum property in the Qt Designer property editor, so that users can select from a list of predefined options rather than typing in arbitrary values.
In C++, it is possible to expose an enum to Qt Designer using Q_ENUMS and Q_PROPERTY, as described in this Stack Overflow question.
I want to achieve the same result in Python. Specifically, I want to:
- Define an enum in Python that can be used as a property in my custom widget.
- Ensure that this enum is displayed as a dropdown list in the Qt Designer property editor.
Here's an outline of what I have so far:
from qtpy.QtCore import Qt, QEasingCurve, QPropertyAnimation, QSize, Property, QPoint, QEnum from qtpy.QtWidgets import QCheckBox, QApplication, QLabel from enum import Enum class EasingCurveEnum(Enum): Option1 = 0 Option2 = 1 Option3 = 2 class QCustomCheckBox(QCheckBox): def __init__(self, parent=None): super().__init__(parent) self._easing_curve = EasingCurveEnum.Option1 # ... @Property(EasingCurveEnum, designable=True) def animationEasingCurve(self): return self._easing_curve @animationEasingCurve.setter def animationEasingCurve(self, curve): self._easing_curve = curveHow can I make the EasingCurveEnum property appear as a list of options in the Qt Designer property editor?
I've successfully registered my custom widget in Qt Designer, but the enum list property is not appearing.
Any guidance or examples would be greatly appreciated!
Thanks in advance!
If solution found, please share it here Stackoverflow post
I guess the same way as in C++. You need to register the enum.
When using Python enums, with
@QEnum -
I guess the same way as in C++. You need to register the enum.
When using Python enums, with
@QEnum@Pl45m4
Am assuming that you're referring to this:@QEnum class EasingCurveEnum(Enum): ....I tried it didnt work.
I also tried this, did not work either:
class EasingCurveEnum(Enum): Option1 = 0 Option2 = 1 Option3 = 2 class QCustomCheckBox(QCheckBox): def __init__(self, parent=None): super().__init__(parent) #tried..... QEnum(EasingCurveEnum) self._easing_curve = EasingCurveEnum.Option1 # ... @Property(EasingCurveEnum, designable=True) def animationEasingCurve(self): return self._easing_curve @animationEasingCurve.setter def animationEasingCurve(self, curve): self._easing_curve = curve -
@Pl45m4
Am assuming that you're referring to this:@QEnum class EasingCurveEnum(Enum): ....I tried it didnt work.
I also tried this, did not work either:
class EasingCurveEnum(Enum): Option1 = 0 Option2 = 1 Option3 = 2 class QCustomCheckBox(QCheckBox): def __init__(self, parent=None): super().__init__(parent) #tried..... QEnum(EasingCurveEnum) self._easing_curve = EasingCurveEnum.Option1 # ... @Property(EasingCurveEnum, designable=True) def animationEasingCurve(self): return self._easing_curve @animationEasingCurve.setter def animationEasingCurve(self, curve): self._easing_curve = curve@Khamisi-Kibet
Please read @Pl45m4's link and the sample there:The enumerator must be in a QObject derived class to be registered.
I know no more than that, nor whether this is the right approach. Try moving your
class EasingCurveEnum(Enum)insideclass QCustomCheckBox(QCheckBox). -
@Pl45m4
Am assuming that you're referring to this:@QEnum class EasingCurveEnum(Enum): ....I tried it didnt work.
I also tried this, did not work either:
class EasingCurveEnum(Enum): Option1 = 0 Option2 = 1 Option3 = 2 class QCustomCheckBox(QCheckBox): def __init__(self, parent=None): super().__init__(parent) #tried..... QEnum(EasingCurveEnum) self._easing_curve = EasingCurveEnum.Option1 # ... @Property(EasingCurveEnum, designable=True) def animationEasingCurve(self): return self._easing_curve @animationEasingCurve.setter def animationEasingCurve(self, curve): self._easing_curve = curveYour enum needs to be part of a
QObjectbased class... otherwise moc / QtDesigner won't notice it.
Check the indentation in my linked example. It's part of theQObjectclass, not a standalone Python enum class.Edit:
What @JonB wrote above :D -
Your enum needs to be part of a
QObjectbased class... otherwise moc / QtDesigner won't notice it.
Check the indentation in my linked example. It's part of theQObjectclass, not a standalone Python enum class.Edit:
What @JonB wrote above :D@Pl45m4 @JonB
Thank you all for your feedback. I read these documentations https://doc.qt.io/qtforpython-6/PySide6/QtCore/QEnum.html , https://doc.qt.io/qtforpython-6.5/PySide6/QtCore/QEnum.html , tried different examples but they didn't work.I also attempted the example below which didn't work as I expected:
class QCustomCheckBox(QCheckBox): @QEnum class EasingCurveEnum(Enum): Option1 = 0 Option2 = 1 Option3 = 2 def __init__(self, parent=None): super().__init__(parent) self._easing_curve = EasingCurveEnum.Option1 # ... @Property(EasingCurveEnum, designable=True) def animationEasingCurve(self): return self._easing_curve @animationEasingCurve.setter def animationEasingCurve(self, curve): self._easing_curve = curveImages showing my custom properties:


-
Hello, is there any update for this issue? I'm also facing the problem that the QEnums properties are not loaded by QtDesigner
-
Coming back (after 2 years ! ) to close this out, since I finally have a solution that's held up in production.
Short answer: you can't get a real inline dropdown in Designer's Property Editor from pure Python. That specific bit needs a compiled C++ plugin. But there's a Python path that works well in practice — I'll explain both.
What doesn't work (so you can skip the dead-ends I hit):
I tried a
QDesignerPropertySheetExtensionto swap the property's editor. On PySide6 6.11:- You can't delegate to Designer's built-in sheet —
extensionManager().extension(...)hands it back as a bareQObjectand shiboken can't recover the real interface, so the methods just aren't there. - Replacing the sheet wholesale with a Python-built one segfaults Designer during form load — even when every property returns a plain string. Its core assumes the internal C++ sheet.
Also worth knowing: declaring the property as a
Q_ENUM/@QEnumdoes give you a dropdown, but only for static, compile-time enums baked into the widget. It's no help if your options are computed at runtime (mine come from a project file), which was the whole point.What actually works — a task-menu extension:
Right-click the widget → your action pops a combo box → you write the choice back through the form cursor. It's undo-aware, dirties the form, and saves to the
.uilike any normal edit.from PySide6.QtDesigner import (QExtensionFactory, QPyDesignerTaskMenuExtension, QDesignerFormWindowInterface) from PySide6.QtGui import QAction from PySide6.QtWidgets import QInputDialog TASKMENU_IID = "org.qt-project.Qt.Designer.TaskMenu" class ThemeTaskMenu(QPyDesignerTaskMenuExtension): def __init__(self, widget, parent=None): super().__init__(parent) self._widget = widget self._action = QAction("Set theme…", self) self._action.triggered.connect(self._choose) def taskActions(self): return [self._action] def _choose(self): names = ["Light", "Dark", "Solarized"] # build this list at runtime current = self._widget.property("appTheme") or "" i = names.index(current) if current in names else 0 name, ok = QInputDialog.getItem(self._widget.window(), "Theme", "Theme:", names, i, False) if not ok or not name: return fw = QDesignerFormWindowInterface.findFormWindow(self._widget) # cursor path = undoable + saved to the .ui; a raw setProperty won't stick (fw.cursor().setWidgetProperty(self._widget, "appTheme", name) if fw else self._widget.setProperty("appTheme", name)) class ThemeTaskMenuFactory(QExtensionFactory): def createExtension(self, obj, iid, parent): if iid != TASKMENU_IID or not isinstance(obj, MyCustomWidget): return None return ThemeTaskMenu(obj, parent)Register it in your plugin's
initialize(core):core.extensionManager().registerExtensions( ThemeTaskMenuFactory(core.extensionManager()), TASKMENU_IID)Two things that bit me:
- Apply via
fw.cursor().setWidgetProperty(...), not justwidget.setProperty(...)— otherwise the change never makes it into the saved.ui. - Keep the underlying property a plain, validated
@Property(str). The menu is only an input aid; the stored value stays portable and works fine on machines without your plugin. - If you have both PyQt5 and PySide6 installed, launch designer with
QT_API=pyside6or qtpy may pick PyQt5 and your plugin import will fail.
So: static enum →
Q_ENUM. Runtime options → task-menu extension. True inline dropdown → C++ only.I use a slightly fancier version of this (a little dock with a combo per property) in my widgets library if anyone wants a fuller reference:
https://github.com/SpinnCompany/QT-PyQt-PySide-Custom-WidgetsMarking this solved — hope it saves someone the segfault hunt.
- You can't delegate to Designer's built-in sheet —
-
K Khamisi Kibet has marked this topic as solved