Custom QStyle for QLabel: Issue with Double Text Rendering
-
Hi,
I'm working on creating a custom QStyle for a QLabel without relying on style sheets.
I've successfully implemented a similar approach for customizing a button's style, and it works as expected.
However, when applying it to the label, I'm encountering an issue where the label renders two overlapping instances of the text.The issue I'm facing is that the label renders two instances of the text.
The first one is painted according to the custom requirements from the code, but the default text rendered by QLabel remains visible and is not removed.
I need to prevent the default rendering and only show the customized version.void AstraLabelStyle::draw(const QStyleOption* option, QPainter* p, const QWidget* widget) const { QWidget* nonConstWidget = const_cast<QWidget*>(widget); QLabel* label = dynamic_cast<QLabel*>(nonConstWidget); mTheme->getState(option); // Sub Elements QString text = label->text(); // Font QFont font(mTheme->fontFamily(), 20, mTheme->fontWeight()); // Compute the total size of subelements QSize eSize; int eSpacing; computeElementsSize(option, label, font, eSize, eSpacing); QRect rect = option->rect; // ------------------------------------------------------------------------------------------------------------- int x = rect.x() + mTheme->paddingH(); ; int y = rect.y() + (rect.height() - eSize.height()) / 2; // Text if (!text.isEmpty()) { p->save(); p->setRenderHint(QPainter::TextAntialiasing, true); QRect textRect(x, y + (eSize.height() - option->fontMetrics.height()) / 2, option->fontMetrics.horizontalAdvance(text) * 1.5, option->fontMetrics.height()); p->setPen(QPen(QBrush(mTheme->foregroundBrush(textRect)), 1)); p->setFont(font); p->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); p->restore(); } }Thanks in advance for your help.
-
At the end I have found the folowing solution:
Now just one text rendering is performed.void AstraApplicationStyle::drawItemText(QPainter* painter, const QRect& rect, int flags, const QPalette& pal, bool enabled, const QString& text, QPalette::ColorRole textRole) const { if (text.isEmpty() || skipLabelTextRendering) { skipLabelTextRendering = false; return; } QProxyStyle::drawItemText(painter, rect, flags, pal, enabled, text, textRole); } void AstraApplicationStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const { //qDebug() << "--> Widget Name: " << widget->objectName() << " (CE: " << element << ")"; QString name = widget->objectName(); switch (element) { case QStyle::CE_ShapedFrame: { // QLabel if (widget && qobject_cast<const QLabel*>(widget)) { skipLabelTextRendering = true; mLabelStyle->draw(option, painter, widget); return; } break; } case QStyle::CE_PushButton: { mButtonStyle->draw(option, painter, widget); return; } default: break; } //Base QProxyStyle::drawControl(element, option, painter, widget); } -
Who calls draw()? It's not a virtual function of QStyle.
-
Hi,
I'm working on creating a custom QStyle for a QLabel without relying on style sheets.
I've successfully implemented a similar approach for customizing a button's style, and it works as expected.
However, when applying it to the label, I'm encountering an issue where the label renders two overlapping instances of the text.The issue I'm facing is that the label renders two instances of the text.
The first one is painted according to the custom requirements from the code, but the default text rendered by QLabel remains visible and is not removed.
I need to prevent the default rendering and only show the customized version.void AstraLabelStyle::draw(const QStyleOption* option, QPainter* p, const QWidget* widget) const { QWidget* nonConstWidget = const_cast<QWidget*>(widget); QLabel* label = dynamic_cast<QLabel*>(nonConstWidget); mTheme->getState(option); // Sub Elements QString text = label->text(); // Font QFont font(mTheme->fontFamily(), 20, mTheme->fontWeight()); // Compute the total size of subelements QSize eSize; int eSpacing; computeElementsSize(option, label, font, eSize, eSpacing); QRect rect = option->rect; // ------------------------------------------------------------------------------------------------------------- int x = rect.x() + mTheme->paddingH(); ; int y = rect.y() + (rect.height() - eSize.height()) / 2; // Text if (!text.isEmpty()) { p->save(); p->setRenderHint(QPainter::TextAntialiasing, true); QRect textRect(x, y + (eSize.height() - option->fontMetrics.height()) / 2, option->fontMetrics.horizontalAdvance(text) * 1.5, option->fontMetrics.height()); p->setPen(QPen(QBrush(mTheme->foregroundBrush(textRect)), 1)); p->setFont(font); p->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); p->restore(); } }Thanks in advance for your help.
@Boltian said in Custom QStyle for QLabel: Issue with Double Text Rendering:
// Text if (!text.isEmpty()) { p->save(); p->setRenderHint(QPainter::TextAntialiasing, true); QRect textRect(x, y + (eSize.height() - option->fontMetrics.height()) / 2, option->fontMetrics.horizontalAdvance(text) * 1.5, option->fontMetrics.height()); p->setPen(QPen(QBrush(mTheme->foregroundBrush(textRect)), 1)); p->setFont(font); p->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); p->restore(); }Hi,
I'm not an expert when it comes to custom
QStyleimplementations, but I wonder what happens, when you remove thesave/restorecalls?Edit:
As @Christian-Ehrlicher said above:
Check the source forQLabelstyle:In
paintEventthestyle->drawItemTextis calledand internally
drawItemTextpaints withpainter->drawText -
Who calls draw()? It's not a virtual function of QStyle.
The draw() method is call up in the general style.
mLabelStyle is a a helper which contains all necessry methods for define the style.void AstraApplicationStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const { QString name = widget->objectName(); switch (element) { case QStyle::CE_ShapedFrame: { // QLabel if (widget && qobject_cast<const QLabel*>(widget)) { mLabelStyle->draw(option, painter, widget); return; } break; } case QStyle::CE_PushButton: { mButtonStyle->draw(option, painter, widget); return; } default: break; } //Base QProxyStyle::drawControl(element, option, painter, widget); } -
At the end I have found the folowing solution:
Now just one text rendering is performed.void AstraApplicationStyle::drawItemText(QPainter* painter, const QRect& rect, int flags, const QPalette& pal, bool enabled, const QString& text, QPalette::ColorRole textRole) const { if (text.isEmpty() || skipLabelTextRendering) { skipLabelTextRendering = false; return; } QProxyStyle::drawItemText(painter, rect, flags, pal, enabled, text, textRole); } void AstraApplicationStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const { //qDebug() << "--> Widget Name: " << widget->objectName() << " (CE: " << element << ")"; QString name = widget->objectName(); switch (element) { case QStyle::CE_ShapedFrame: { // QLabel if (widget && qobject_cast<const QLabel*>(widget)) { skipLabelTextRendering = true; mLabelStyle->draw(option, painter, widget); return; } break; } case QStyle::CE_PushButton: { mButtonStyle->draw(option, painter, widget); return; } default: break; } //Base QProxyStyle::drawControl(element, option, painter, widget); } -
B Boltian has marked this topic as solved on