QMessageBox subclass has different appearance from base class in macOS (even when calling base constructor)
-
In macOS, creating a QMessageBox directly has a completely different appearance than creating a subclass, no matter how barebones the subclass is.
For instance, here is a base QMessageBox
from PyQt6.QtWidgets import QApplication, QMessageBox app = QApplication([]) q = QMessageBox() q.setText("hello world") q.exec()
And here is a subclass of QMessageBox
from PyQt6.QtWidgets import QApplication, QMessageBox app = QApplication([]) class MyMessageBox(QMessageBox): def __init__(self): super().__init__() q = MyMessageBox() q.setText("hello world") q.exec()
Does anyone know why this happens and how to make the subclass look like the base one?
This is a fixed post, since my last one was misunderstood.
I have also tried callingsuper().__new__
, (yes, within the right context) -
Hi,
Do you get the same issue if using PySide6 ?
Which version of Python are you using ?
Which version of PySide6 ?
How did you install them ?
On which version of macOS ? -
Also maybe this can be worked-around. What is your goal for subclassing QMessageBox? Can this be achieved in another way?
My random guess is that only non-subclassed QMessageBox get the native look while subclasses get a generic one allowing them to be customized.
-
So I tested this, its the same for pyside6
@GrecKo that shouldn't be really possible, right? It's a direct subclass of QMessageBox it should use the same styles, call the same functions, as non are overridden.
Maybe it's a global stylesheet ? IIRC those can have a Class-Tag and could potentially no longer apply to derived classes🤔
-
So I tested this, its the same for pyside6
@GrecKo that shouldn't be really possible, right? It's a direct subclass of QMessageBox it should use the same styles, call the same functions, as non are overridden.
Maybe it's a global stylesheet ? IIRC those can have a Class-Tag and could potentially no longer apply to derived classes🤔
@J-Hilk said in QMessageBox subclass has different appearance from base class in macOS (even when calling base constructor):
@GrecKo that shouldn't be really possible, right? It's a direct subclass of QMessageBox it should use the same styles, call the same functions, as non are overridden.
Not necessarily. This was my thought too yesterday, but I didn't feel like replying in view of the vitriol. Although it is unusual for code to check whether something is a subclass rather that actually of a certain class exactly it is not impossible. My hunch was that code (maybe Mac only, maybe not) only uses some "native" style when object is
QMessageBox
but not subclass. Perhaps because it considers that once you subclass all bets are off for using "native" as it does not know what you are going to do. A little bit like when you do style on some widgets they change from "native" style. One would have to check code. -
@J-Hilk said in QMessageBox subclass has different appearance from base class in macOS (even when calling base constructor):
@GrecKo that shouldn't be really possible, right? It's a direct subclass of QMessageBox it should use the same styles, call the same functions, as non are overridden.
Not necessarily. This was my thought too yesterday, but I didn't feel like replying in view of the vitriol. Although it is unusual for code to check whether something is a subclass rather that actually of a certain class exactly it is not impossible. My hunch was that code (maybe Mac only, maybe not) only uses some "native" style when object is
QMessageBox
but not subclass. Perhaps because it considers that once you subclass all bets are off for using "native" as it does not know what you are going to do. A little bit like when you do style on some widgets they change from "native" style. One would have to check code.@JonB Qt classes don't require/use RTTI so It would have to be some Qt equivalent to
typeid
after a Quick Look into the dokumention, QObject has inherits(), but "A class is considered to inherit itself." So that doesn't work.
All other methods I can think of would require the method to know about the derived class beforehand 🤷♂️
-
metaObject()->className() == "QMessageBox"
does the trick. -
@JonB Qt classes don't require/use RTTI so It would have to be some Qt equivalent to
typeid
after a Quick Look into the dokumention, QObject has inherits(), but "A class is considered to inherit itself." So that doesn't work.
All other methods I can think of would require the method to know about the derived class beforehand 🤷♂️
@J-Hilk said in QMessageBox subclass has different appearance from base class in macOS (even when calling base constructor):
@JonB Qt classes don't require/use RTTI so It would have to be some Qt equivalent to typeid
Ah. I believe Python can test this, and OP is using Python, but one would not have thought there would be special Python code here.
Fair enough. It leaves us at a bit of a loss then where OP shows a completely different style for a derived
QMessageBox
from a base one.... -
@GrecKo said in QMessageBox subclass has different appearance from base class in macOS (even when calling base constructor):
metaObject()->className() == "QMessageBox" does the trick.
Yes indeed. I don't how likely it is that either all Qt code or perhaps MacOS-specific implementation for calling native
QMessageBox
would do this? -
It's done here : https://github.dev/qt/qtbase/blob/308bca94a72f83624e2e2c92449719e06940e77f/src/widgets/dialogs/qmessagebox.cpp#L2800-L2801
Commit with its comments can be found here : https://codereview.qt-project.org/c/qt/qtbase/+/472618
I guess PyQt6 automatically defines Q_OBJECT for Qt subclasses?
-
It's done here : https://github.dev/qt/qtbase/blob/308bca94a72f83624e2e2c92449719e06940e77f/src/widgets/dialogs/qmessagebox.cpp#L2800-L2801
Commit with its comments can be found here : https://codereview.qt-project.org/c/qt/qtbase/+/472618
I guess PyQt6 automatically defines Q_OBJECT for Qt subclasses?
@GrecKo
Absolutely perfect, thanks for finding this! So it does do what I suspected it might :)P.S.
I would assume this is also the case for other dialogs etc. where there is a "native" implementation on offer, e.g.QFileDialog
? Once Qt sees it has been subclassed it does not know what you might be doing/adding so it moves over to a Qt-non-native implementation so that it will "work". For the native ones you can use whatever it might allow for its own configuration (e.g. perhaps styling) but you must not subclass. Maybe documentation should mention this? -
Reading the comments in the commit it appears this is not an intended behavior, and it was considered not that big of a deal since not many subclasses would use Q_OBJECT to declare a descendant metaobject. PyQt appears to do so though, that is a bit unfortunate in this case.
This warrants a bug report on Qt's JIRA and then it goes back to my initial question: Why subclass QMessageBox?
-
Reading the comments in the commit it appears this is not an intended behavior, and it was considered not that big of a deal since not many subclasses would use Q_OBJECT to declare a descendant metaobject. PyQt appears to do so though, that is a bit unfortunate in this case.
This warrants a bug report on Qt's JIRA and then it goes back to my initial question: Why subclass QMessageBox?
@GrecKo said in QMessageBox subclass has different appearance from base class in macOS (even when calling base constructor):
since not many subclasses would use Q_OBJECT to declare a descendant metaobject
Ohhh! You are saying that only if you use
Q_OBJECT
in a subclass doesmetaObject()->className()
get changed to the subclass name?! I did not get that from your earlier post and did not understand howQ_OBJECT
was relevant. It would not surprise me if PyQt or PySide automatically didQ_OBJECT
, don't think that exists for the Python user.I am not volunteering to report this, if you feel like it that's up to you.
So if OP could prevent that from PyQt then he would get away with subclassing.
I do not know why he feels he wants to subclass. He may have to rethink in light of this discovery.