Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Q_ENUMS in PyQt

I am creating a custom widget that inherits from QLabel, and I would like to have a property on my widget to represent how the data must be formatted when presenting to the user.

For that I am trying to use Q_ENUMS, but I'm not having much success. I can get the property to show in Designer, but the UI file saved shows the enum as PyDMLabel::STRING and not as I would expect DisplayFormat::STRING.

Here is my code for the widget:

class PyDMLabel(QLabel, PyDMWidget):
    class DisplayFormat:
        DEFAULT = 0
        STRING = 1
        DECIMAL = 2
        EXPONENTIAL = 3
        HEX = 4
        BINARY = 5

    Q_ENUMS(DisplayFormat)

    """
    A QLabel with support for Channels and more from PyDM

    Parameters
    ----------
    parent : QWidget
        The parent widget for the Label
    init_channel : str, optional
        The channel to be used by the widget.
    """
    def __init__(self, parent=None, init_channel=None):
        QLabel.__init__(self, parent)
        PyDMWidget.__init__(self, init_channel=init_channel)

        self.setTextFormat(Qt.PlainText)
        self.setTextInteractionFlags(Qt.NoTextInteraction)
        self.setText("PyDMLabel")
        self._display_format_type = PyDMLabel.DisplayFormat.DEFAULT

    @pyqtProperty(DisplayFormat)
    def displayFormat(self):
        return self._display_format_type

    @displayFormat.setter
    def displayFormat(self, new_type):
        if self._display_format_type != new_type:
            self._display_format_type = new_type

What is the correct way to deal with Q_ENUMS and PyQt?

like image 844
hhslepicka Avatar asked Jan 17 '26 15:01

hhslepicka


1 Answers

UPDATE:

As of PyQt-5.11, Q_ENUMS/Q_FLAGS have been deprecated, so that Q_ENUM/Q_FLAG should be used instead. This does not affect the original solution given below, which will still work with either Q_ENUM or Q_ENUMS. However, in PyQt6, these functions are no longer available and have been replaced by pyqtEnum. This means user-defined enums must now be subclasses of enum.Enum and be decorated accordingly. For consistency with the built-in APIs, they should probably also be fully scoped (i.e. so that PyDMLabel.STRING is no longer allowed), but this is not strictly necessary:

from enum import Enum
from PyQt6.QtCore import pyqtEnum

@pyqtEnum
class DisplayFormat(Enum):
    DEFAULT = 0
    STRING = 1
    DECIMAL = 2
    EXPONENTIAL = 3
    HEX = 4
    BINARY = 5

class PyDMLabel(QLabel, PyDMWidget):
    DisplayFormat = DisplayFormat

Original Solution (PyQt5):

In order for Qt (Designer) to see an enum, PyQt has to add it to the meta-object of the custom class. So it could never be referred to by Qt as DisplayFormat::STRING.

In Qt, enums declared in the class scope expose their constants as members of the class. So for example, the QComboBox class defines an InsertPolicy enum, and the constants can be referred to like this: QComboBox::InsertAtTop. So in that respect, the behaviour of PyQt enums in Qt Designer plugins is exactly as expected, since the ui file shows PyDMLabel::STRING.

However, getting fully equivalent behaviour in Python code requires some extra work. The nearest I could come up with is this:

class DisplayFormat:
    DEFAULT = 0
    STRING = 1
    DECIMAL = 2
    EXPONENTIAL = 3
    HEX = 4
    BINARY = 5

class PyDMLabel(QLabel, PyDMWidget, DisplayFormat):
    DisplayFormat = DisplayFormat

    Q_ENUM(DisplayFormat)

This will still result in Qt Designer using PyDMLabel::STRING (as expected). But Python code can now access the constants in any of these ways:

PyDMLabel.STRING
PyDMLabel.DisplayFormat.STRING
DisplayFormat.STRING

And in fact, if you don't mind losing the second of these options, you could simplify things even further to this:

class DisplayFormat:
    DEFAULT = 0
    ...    

class PyDMLabel(QLabel, PyDMWidget, DisplayFormat):    
    Q_ENUM(DisplayFormat)

PS:

In PyQt5, it does not matter what the type of the enum class is - so it could be a subclass of int, a plain object, or even a python enum.

like image 91
ekhumoro Avatar answered Jan 20 '26 06:01

ekhumoro



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!