Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Qt Designer: Display a List of Enum Options in Custom Widget Properties Editor Using Python
Qt 6.11 is out! See what's new in the release blog

Qt Designer: Display a List of Enum Options in Custom Widget Properties Editor Using Python

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 4 Posters 2.7k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    Khamisi Kibet
    wrote on last edited by
    #1

    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 = curve
    
    

    How 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

    Pl45m4P 1 Reply Last reply
    0
    • K Offline
      K Offline
      Khamisi Kibet
      wrote last edited by
      #8

      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 QDesignerPropertySheetExtension to 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 bare QObject and 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/@QEnum does 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 .ui like 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 just widget.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=pyside6 or 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-Widgets

      Marking this solved — hope it saves someone the segfault hunt.

      1 Reply Last reply
      0
      • K Khamisi Kibet

        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 = curve
        
        

        How 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

        Pl45m4P Offline
        Pl45m4P Offline
        Pl45m4
        wrote on last edited by
        #2

        @Khamisi-Kibet

        I guess the same way as in C++. You need to register the enum.

        When using Python enums, with @QEnum

        • https://doc.qt.io/qtforpython-6/PySide6/QtCore/QEnum.html

        If debugging is the process of removing software bugs, then programming must be the process of putting them in.

        ~E. W. Dijkstra

        K 1 Reply Last reply
        0
        • Pl45m4P Pl45m4

          @Khamisi-Kibet

          I guess the same way as in C++. You need to register the enum.

          When using Python enums, with @QEnum

          • https://doc.qt.io/qtforpython-6/PySide6/QtCore/QEnum.html
          K Offline
          K Offline
          Khamisi Kibet
          wrote on last edited by Khamisi Kibet
          #3

          @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
          
          
          
          JonBJ Pl45m4P 2 Replies Last reply
          0
          • K Khamisi Kibet

            @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
            
            
            
            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by JonB
            #4

            @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) inside class QCustomCheckBox(QCheckBox).

            1 Reply Last reply
            1
            • K Khamisi Kibet

              @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
              
              
              
              Pl45m4P Offline
              Pl45m4P Offline
              Pl45m4
              wrote on last edited by Pl45m4
              #5

              @Khamisi-Kibet

              Your enum needs to be part of a QObject based class... otherwise moc / QtDesigner won't notice it.
              Check the indentation in my linked example. It's part of the QObject class, not a standalone Python enum class.

              Edit:
              What @JonB wrote above :D


              If debugging is the process of removing software bugs, then programming must be the process of putting them in.

              ~E. W. Dijkstra

              K 1 Reply Last reply
              0
              • Pl45m4P Pl45m4

                @Khamisi-Kibet

                Your enum needs to be part of a QObject based class... otherwise moc / QtDesigner won't notice it.
                Check the indentation in my linked example. It's part of the QObject class, not a standalone Python enum class.

                Edit:
                What @JonB wrote above :D

                K Offline
                K Offline
                Khamisi Kibet
                wrote on last edited by Khamisi Kibet
                #6

                @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 = curve
                

                Images showing my custom properties:

                Screenshot 2024-08-29 103702.png

                Screenshot 2024-08-29 103626.png

                1 Reply Last reply
                0
                • D Offline
                  D Offline
                  danielhrisca
                  wrote on last edited by
                  #7

                  Hello, is there any update for this issue? I'm also facing the problem that the QEnums properties are not loaded by QtDesigner

                  1 Reply Last reply
                  0
                  • K Offline
                    K Offline
                    Khamisi Kibet
                    wrote last edited by
                    #8

                    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 QDesignerPropertySheetExtension to 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 bare QObject and 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/@QEnum does 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 .ui like 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 just widget.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=pyside6 or 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-Widgets

                    Marking this solved — hope it saves someone the segfault hunt.

                    1 Reply Last reply
                    0
                    • K Khamisi Kibet has marked this topic as solved

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved