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. stylesheet magic: setfont + polish = wrong background
QtWS25 Last Chance

stylesheet magic: setfont + polish = wrong background

Scheduled Pinned Locked Moved Solved General and Desktop
solved
13 Posts 4 Posters 2.3k Views
  • 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.
  • D Offline
    D Offline
    DaveMilter
    wrote on 8 Dec 2018, 03:39 last edited by DaveMilter
    #1

    The code bellow is complete magic for me,
    anybody can explain magic behind the scene?
    I haveMyW with white backgroud and expect that it's child QLabel,
    also will have white background. But this not happens.
    I found three way to fix this, but I completly do not understand why this fix the issue:

    1. Do not call lbl->ensurePolish(),
    2. Set full style with one call in MyW
    3. Remove code that setFont in MyW

    But how font involve on background, or why the place of call of ensurePolish is important (if I don't call it in MyW::MyW it called later on show) , these things are completly mystery for me.

    #include <QApplication>
    #include <QLabel>
    #include <QVBoxLayout>
    #include <QtDebug>
    
    class MyW : public QWidget {
    public:
      MyW(QWidget *parent) : QWidget(parent) {
        setStyleSheet("border:none;");
    
        auto font = QApplication::font();
        if (font.pixelSize() != -1) {
          font.setPixelSize(static_cast<int>(font.pixelSize() * 1.25 + 0.5));
          setFont(font);
        }
    
        setStyleSheet(styleSheet() + "background:#ffffff;color:#000000;");
    
        auto lbl = new QLabel{"AAAA", this};
        auto lay = new QVBoxLayout;
        setLayout(lay);
        lay->addWidget(lbl);
        lbl->ensurePolished();
      }
    };
    
    class Page : public QWidget {
    public:
      Page(QWidget *parent) : QWidget{parent} {
        setStyleSheet("background:#f0f4f7;");
        auto lay = new QVBoxLayout;
        setLayout(lay);
        auto item = new MyW{this};
        lay->addWidget(item);
      }
    };
    
    int main(int argc, char *argv[]) {
      QApplication a(argc, argv);
    
      QFont font("Arial");
      font.setFixedPitch(false);
      font.setBold(true);
      font.setPixelSize(30);
      qInfo() << "font pixel size " << font.pixelSize();
      QApplication::setFont(font);
    
      Page p{nullptr};
      p.resize(400, 800);
      p.show();
      return a.exec();
    }
    
    1 Reply Last reply
    0
    • D Offline
      D Offline
      dheerendra
      Qt Champions 2022
      wrote on 8 Dec 2018, 04:18 last edited by dheerendra 12 Aug 2018, 04:19
      #2

      It is because of ensurePolish your magic is happening. It ensures that all label is applied with Styles again.If you move the statement above line#22(above VLayout), label is polished then & there. After this label becomes child of MyW once you add into layout. So now styles of parent applied. It all depends when the label becomes the child of MyW. Hope magic is clear now.

      Dheerendra
      @Community Service
      Certified Qt Specialist
      http://www.pthinks.com

      D 1 Reply Last reply 8 Dec 2018, 04:32
      0
      • D dheerendra
        8 Dec 2018, 04:18

        It is because of ensurePolish your magic is happening. It ensures that all label is applied with Styles again.If you move the statement above line#22(above VLayout), label is polished then & there. After this label becomes child of MyW once you add into layout. So now styles of parent applied. It all depends when the label becomes the child of MyW. Hope magic is clear now.

        D Offline
        D Offline
        DaveMilter
        wrote on 8 Dec 2018, 04:32 last edited by DaveMilter 12 Aug 2018, 04:33
        #3

        @dheerendra

        After this label becomes child of MyW once you add into layout
        Hope magic is clear now.

        Hm, nothing is clear. label become child after this:
        auto lbl = new QLabel{"AAAA", this};

        you see I pass this as argument for QLabel::QLabel(const QString &text, QWidget *parent, Qt::WindowFlags = ...), why you think that adding to layout change parent or something?

        Also this is not explain why setFont change background, and why

        setStyleSheet("border:none;");
        setStyleSheet(styleSheet() + "background:#ffffff;color:#000000;");
        

        and setStyleSheet("border:none;background:#ffffff;color:#000000;"); gives different results

        1 Reply Last reply
        0
        • D Offline
          D Offline
          dheerendra
          Qt Champions 2022
          wrote on 8 Dec 2018, 05:58 last edited by
          #4

          I did not notice 'this' is passed while constructing. So parent will not change. If you put polished at the end, it will apply this. Can you look ensurePolished method(). It gives you the idea how it works. Last applied style are taking for label rather from parent. If you move up the polished, last applied styles are from parent.

          Dheerendra
          @Community Service
          Certified Qt Specialist
          http://www.pthinks.com

          1 Reply Last reply
          0
          • N Offline
            N Offline
            NicolasS
            wrote on 8 Dec 2018, 08:09 last edited by
            #5

            Also from the doc:

            If you subclass from QWidget, you need to provide a paintEvent for your custom QWidget as below:
            
             void CustomWidget::paintEvent(QPaintEvent *)
             {
                 QStyleOption opt;
                 opt.init(this);
                 QPainter p(this);
                 style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
             }
            
            The above code is a no-operation if there is no stylesheet set.
            
            Warning: Make sure you define the Q_OBJECT macro for your custom widget.
            

            Source: http://doc.qt.io/qt-5/stylesheet.html

            D 1 Reply Last reply 8 Dec 2018, 09:43
            0
            • N NicolasS
              8 Dec 2018, 08:09

              Also from the doc:

              If you subclass from QWidget, you need to provide a paintEvent for your custom QWidget as below:
              
               void CustomWidget::paintEvent(QPaintEvent *)
               {
                   QStyleOption opt;
                   opt.init(this);
                   QPainter p(this);
                   style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
               }
              
              The above code is a no-operation if there is no stylesheet set.
              
              Warning: Make sure you define the Q_OBJECT macro for your custom widget.
              

              Source: http://doc.qt.io/qt-5/stylesheet.html

              D Offline
              D Offline
              DaveMilter
              wrote on 8 Dec 2018, 09:43 last edited by
              #6

              @NicolasS

              If you subclass from QWidget

              The problem completly reproducible with Q_OBJECT and paintEvent override for MyW and Page, so I remove this code to make example smaller and fit it to one c++ file.

              1 Reply Last reply
              0
              • mrjjM Offline
                mrjjM Offline
                mrjj
                Lifetime Qt Champion
                wrote on 8 Dec 2018, 10:30 last edited by
                #7

                Hi
                Just as a note
                void CustomWidget::paintEvent(QPaintEvent *)
                {
                QStyleOption opt;
                opt.init(this);
                QPainter p(this);
                style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
                }

                • The above code is a no-operation if there is no stylesheet set.

                Its not a no-operation. the QStyle::PE_Widget style is just very basic and have no background color or frame.
                most other QStyle::PE_xxxx are a bit more interesting :)

                Regarding your issue.
                You are not using any selectors in the your style sheets and since
                sheets are cascading ( affects children too) ,
                it often result in a mess assigning style sheet through the whole program.

                so what color do the label get ?
                I would guess on #f0f4f7 ?

                D 1 Reply Last reply 8 Dec 2018, 10:42
                2
                • mrjjM mrjj
                  8 Dec 2018, 10:30

                  Hi
                  Just as a note
                  void CustomWidget::paintEvent(QPaintEvent *)
                  {
                  QStyleOption opt;
                  opt.init(this);
                  QPainter p(this);
                  style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
                  }

                  • The above code is a no-operation if there is no stylesheet set.

                  Its not a no-operation. the QStyle::PE_Widget style is just very basic and have no background color or frame.
                  most other QStyle::PE_xxxx are a bit more interesting :)

                  Regarding your issue.
                  You are not using any selectors in the your style sheets and since
                  sheets are cascading ( affects children too) ,
                  it often result in a mess assigning style sheet through the whole program.

                  so what color do the label get ?
                  I would guess on #f0f4f7 ?

                  D Offline
                  D Offline
                  DaveMilter
                  wrote on 8 Dec 2018, 10:42 last edited by DaveMilter 12 Aug 2018, 10:44
                  #8

                  @mrjj

                  You are not using any selectors in the your style

                  Yep, this is intented, I have only two background colors in whole program,
                  and I want that all widgets have them. And I expect

                  http://doc.qt.io/qt-5/stylesheet-syntax.html#cascading

                  When conflicts arise, the widget's own style sheet is always preferred to any inherited style sheet, irrespective of the specificity of the conflicting rules. Likewise, the parent widget's style sheet is preferred to the grandparent's, etc.

                  And sometimes and I get this behaviour for example if I remove lbl->ensurePolish()

                  so what color do the label get ?
                  I would guess on #f0f4f7 ?

                  Yes #f0f4f7 while I expect #ffffff and can get it by three ways:

                  • Do not call lbl->ensurePolish() in MyW::MyW
                  • Set full style with one call of setStyleSheet instead of two in MyW::MyW
                  • Remove code that setFont in MyW::MyW
                  mrjjM 1 Reply Last reply 8 Dec 2018, 10:50
                  0
                  • D DaveMilter
                    8 Dec 2018, 10:42

                    @mrjj

                    You are not using any selectors in the your style

                    Yep, this is intented, I have only two background colors in whole program,
                    and I want that all widgets have them. And I expect

                    http://doc.qt.io/qt-5/stylesheet-syntax.html#cascading

                    When conflicts arise, the widget's own style sheet is always preferred to any inherited style sheet, irrespective of the specificity of the conflicting rules. Likewise, the parent widget's style sheet is preferred to the grandparent's, etc.

                    And sometimes and I get this behaviour for example if I remove lbl->ensurePolish()

                    so what color do the label get ?
                    I would guess on #f0f4f7 ?

                    Yes #f0f4f7 while I expect #ffffff and can get it by three ways:

                    • Do not call lbl->ensurePolish() in MyW::MyW
                    • Set full style with one call of setStyleSheet instead of two in MyW::MyW
                    • Remove code that setFont in MyW::MyW
                    mrjjM Offline
                    mrjjM Offline
                    mrjj
                    Lifetime Qt Champion
                    wrote on 8 Dec 2018, 10:50 last edited by
                    #9

                    @DaveMilter
                    Ok, Do note that QApplication also have setStyleSheet allowing to affect all widgets in app.
                    Could you try
                    ui->label->parent()->objectName();
                    and see whom its daddy ? ( after inserted into layout)

                    D 1 Reply Last reply 8 Dec 2018, 11:05
                    1
                    • mrjjM mrjj
                      8 Dec 2018, 10:50

                      @DaveMilter
                      Ok, Do note that QApplication also have setStyleSheet allowing to affect all widgets in app.
                      Could you try
                      ui->label->parent()->objectName();
                      and see whom its daddy ? ( after inserted into layout)

                      D Offline
                      D Offline
                      DaveMilter
                      wrote on 8 Dec 2018, 11:05 last edited by
                      #10

                      @mrjj

                      Ok, Do note that QApplication also have setStyleSheet allowing to affect all widgets in app.
                      Could you try
                      ui->label->parent()->objectName();
                      and see whom its daddy ? ( after inserted into layout)

                      Why you all are so suspicious about layout,
                      I remove in code bellow all stuff related to layout.
                      And print "family tree" of QLabel:

                      font pixel size  30
                      qapp style:  ""
                      Page:  QWidget(0x7ffee3a13190)
                      MyW:  QWidget(0x559fb05749d0)
                      lbl family tree
                      lbl parent  0 th gen  QLabel(0x7effb0005560)
                      lbl parent  1 th gen  QWidget(0x559fb05749d0)
                      lbl parent  2 th gen  QWidget(0x7ffee3a13190)
                      
                      #include <QApplication>
                      #include <QLabel>
                      #include <QtDebug>
                      
                      class MyW : public QWidget {
                      public:
                        MyW(QWidget *parent) : QWidget(parent) {
                          qDebug() << "MyW: " << static_cast<QObject *>(this);
                          setStyleSheet("border:none;");
                      
                          auto font = QApplication::font();
                          if (font.pixelSize() != -1) {
                            font.setPixelSize(static_cast<int>(font.pixelSize() * 1.25 + 0.5));
                            setFont(font);
                          }
                      
                          setStyleSheet(styleSheet() + "background:#ffffff;color:#000000;");
                      
                          auto lbl = new QLabel{"AAAA", this};
                          {
                            qDebug("lbl family tree");
                            QObject *o = lbl;
                            int i = 0;
                            while (o != nullptr) {
                              qDebug() << "lbl parent " << i << "th gen " << o;
                              ++i;
                              o = o->parent();
                            }
                          }
                          lbl->ensurePolished();
                        }
                      };
                      
                      class Page : public QWidget {
                      public:
                        Page(QWidget *parent) : QWidget{parent} {
                          qDebug() << "Page: " << static_cast<QObject *>(this);
                          setStyleSheet("background:#f0f4f7;");
                          auto item = new MyW{this};
                        }
                      };
                      
                      int main(int argc, char *argv[]) {
                        QApplication a(argc, argv);
                      
                        QFont font("Arial");
                        font.setFixedPitch(false);
                        font.setBold(true);
                        font.setPixelSize(30);
                        qInfo() << "font pixel size " << font.pixelSize();
                        QApplication::setFont(font);
                        qDebug() << "qapp style: " << a.styleSheet();
                        Page p{nullptr};
                        p.resize(400, 800);
                        p.show();
                        return a.exec();
                      }
                      ```
                      1 Reply Last reply
                      0
                      • mrjjM Offline
                        mrjjM Offline
                        mrjj
                        Lifetime Qt Champion
                        wrote on 8 Dec 2018, 11:41 last edited by mrjj 12 Aug 2018, 11:42
                        #11

                        Hi
                        I think the multiple setting of stylesheet in ctor confuses it.
                        if you ensurePolished() for myW it seems to work as expected.
                        (using Parent style sheet)

                        class MyW : public QWidget
                        {
                        public:
                            MyW(QWidget *parent) : QWidget(parent)
                            {
                                qDebug() << "MyW: " << static_cast<QObject *>(this);
                                setStyleSheet("border:none;");
                                ensurePolished(); // <<<<<<<<<<<<<<<<<<<<<<<<<
                        
                                auto font = QApplication::font();
                                if (font.pixelSize() != -1) {
                                    font.setPixelSize(static_cast<int>(font.pixelSize() * 1.25 + 0.5));
                                    setFont(font);
                                }
                        
                                setStyleSheet(styleSheet() + "background:#ffffff;color:#000000;");
                        
                                auto lbl = new QLabel{"AAAA", this};        
                                lbl->ensurePolished(); // not needed
                            }
                        };
                        
                        
                        D 1 Reply Last reply 8 Dec 2018, 12:42
                        0
                        • mrjjM mrjj
                          8 Dec 2018, 11:41

                          Hi
                          I think the multiple setting of stylesheet in ctor confuses it.
                          if you ensurePolished() for myW it seems to work as expected.
                          (using Parent style sheet)

                          class MyW : public QWidget
                          {
                          public:
                              MyW(QWidget *parent) : QWidget(parent)
                              {
                                  qDebug() << "MyW: " << static_cast<QObject *>(this);
                                  setStyleSheet("border:none;");
                                  ensurePolished(); // <<<<<<<<<<<<<<<<<<<<<<<<<
                          
                                  auto font = QApplication::font();
                                  if (font.pixelSize() != -1) {
                                      font.setPixelSize(static_cast<int>(font.pixelSize() * 1.25 + 0.5));
                                      setFont(font);
                                  }
                          
                                  setStyleSheet(styleSheet() + "background:#ffffff;color:#000000;");
                          
                                  auto lbl = new QLabel{"AAAA", this};        
                                  lbl->ensurePolished(); // not needed
                              }
                          };
                          
                          
                          D Offline
                          D Offline
                          DaveMilter
                          wrote on 8 Dec 2018, 12:42 last edited by
                          #12

                          @mrjj

                          I think the multiple setting of stylesheet in ctor confuses it.
                          if you ensurePolished() for myW it seems to work as expected.

                          yeah, but this is not explain why if I remove setFont from MyW::MyW
                          multiple setting of stylesheet works completly fine,
                          without extra call of MyW::ensurePolished,

                          also if I change MyW::MyW to this all works fine (white background),
                          so setFont somehow become interference

                            MyW(QWidget *parent) : QWidget(parent) {
                              qDebug() << "MyW: " << static_cast<QObject *>(this);
                              setStyleSheet("border:none;");
                              setStyleSheet(styleSheet() + "background:#ffffff;color:#000000;");
                              auto font = QApplication::font();
                              if (font.pixelSize() != -1) {
                                font.setPixelSize(static_cast<int>(font.pixelSize() * 1.25 + 0.5));
                                setFont(font);
                              }
                              auto lbl = new QLabel{"AAAA", this};
                              lbl->ensurePolished();
                          }
                          
                          1 Reply Last reply
                          0
                          • D Offline
                            D Offline
                            DaveMilter
                            wrote on 26 Jan 2019, 12:57 last edited by
                            #13

                            I solved this question with SO help: https://stackoverflow.com/questions/53675808/mix-setstylesheet-and-setfont-wrong-background

                            1 Reply Last reply
                            2

                            • Login

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