Question regarding enums and IntEnum/IntFlags

Nyall Dawson nyall.dawson at gmail.com
Sun Feb 18 23:09:09 GMT 2024


On Sat, 17 Feb 2024 at 09:13, Florian Bruhin <me at the-compiler.org> wrote:
>
> Hey,
>
> > I'm wondering if there's a specific reason why some Qt enums are exposed as
> > IntEnum/IntFlags, and others not?
>
> They're exposed as IntEnum/IntFlag if the underlying C++ API uses them
> in such a way - e.g. QEvent.Type (due to QEvent.Type.User), or
> Qt.ItemDataRole (Qt.ItemDataRole.UserRole) or QUrl.UrlFormattingOption
> (can be mixed with Qt.ComponentFormttingOption).

Ok, on second thoughts I agree about Qt.ItemFlag, that's fine to be a
Flags type enum.

>
> > Specifically, I'm looking at Qt.ItemFlag (which I'd have expected to be an
> > IntFlags type) and Qt.CheckState (which I'd expected to be an IntEnum type).

But looking at the Qt.CheckState situation -- from custom models it's
typical to see a ::data implementation which does something like:

switch ( role )
  ...
  case Qt::CheckStateRole:
     return some condition ? Qt::Unchecked : Qt::Checked;

(And this is what Qt internal code does too. See eg
https://github.com/qt/qtbase/blob/adc0920c48d812fb1b3e2b7bfc76217a7126a41e/src/widgets/itemviews/qtreewidget.cpp#L1828

but this means that Python data(...) from Python and querying the
CheckStateRole returns just an integer value. And then if the Python
code tries to do something like:

 if model.data(index, Qt.ItemDataRole.CheckStateRole) ==
Qt.CheckState.Unchecked:
    # something

then the condition will NEVER be met, because model.data( ... ) will
return just an integer 0, and 0 != Qt.CheckState.Unchecked (unless
Qt.CheckState was an IntEnum).

Things work as expected if the c++ ::data implementation does something like:

case Qt::CheckStateRole:
   return some condition ? QVariant::fromValue( Qt::Unchecked ) :
QVariant::fromValue( Qt::Checked );

because then the Python call to .data returns an Qt.CheckState enum
value. But this seems to go against Qt design, and again it's not an
approach used in the Qt internal c++ code either.

So the difference to me seems to be whether a model (or any c++
function implementation) is expected to return the "raw" enum value as
a QVariant, and not a QFlags wrapper around it. If it's expected to
return the raw enum value then that enum needs to be an IntEnum /
IntFlags type to consistently work for different model
implementations.

Nyall






>
> Why?
>
> Florian


More information about the PyQt mailing list