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. How to stop a checkable button from automatically rendering differently when checked?
Forum Updated to NodeBB v4.3 + New Features

How to stop a checkable button from automatically rendering differently when checked?

Scheduled Pinned Locked Moved Unsolved General and Desktop
18 Posts 5 Posters 1.7k Views 3 Watching
  • 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.
  • R RickyRister

    I have an app with several checkable QToolButtons. By default, when a button becomes checked, the button will darken to indicate that it is checked.

    I want one of the buttons to change its icon instead of darkening when checked. I managed to get the icon to change depending on state. However, the button still darkens when checked. Is there a way to turn off that default behavior for that one button specifically?

    Pl45m4P Offline
    Pl45m4P Offline
    Pl45m4
    wrote on last edited by Pl45m4
    #5

    @RickyRister

    Try a stylesheet, where you specify the QToolButton:checked { ..... } style


    If debugging is the process of removing software bugs, then programming must be the process of putting them in.

    ~E. W. Dijkstra

    R 1 Reply Last reply
    1
    • Pl45m4P Pl45m4

      @RickyRister

      Try a stylesheet, where you specify the QToolButton:checked { ..... } style

      R Offline
      R Offline
      RickyRister
      wrote on last edited by
      #6

      @Pl45m4

      Is there something I can put in the QToolButton:checked { ..... } that would make it inherit the color from the unchecked button?
      The app supports multiple color themes, so I don't want to hardcode the color on that one button.

      JonBJ 1 Reply Last reply
      0
      • R RickyRister

        @Pl45m4

        Is there something I can put in the QToolButton:checked { ..... } that would make it inherit the color from the unchecked button?
        The app supports multiple color themes, so I don't want to hardcode the color on that one button.

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #7
        This post is deleted!
        1 Reply Last reply
        0
        • S Offline
          S Offline
          SimonSchroeder
          wrote on last edited by
          #8

          Using a stylesheet is also the first thing that comes to mind. But, I don't think there is a way to inherit the unchecked style.

          The next solution will be a little bit more involved (and you have to do some research because I'm fuzzy on the details). QWidget has a function setStyle(). The QStyle is responsible for actually drawing GUI elements (usually forwarding to system drawing functions). You could inherit from QStyle and override drawControl(). Just handle the one specific case of a checked tool button (just draw it unchecked). Everything else you can then forward to QApplication::style() for rendering. Then, set this style on the tool button(s).

          1 Reply Last reply
          0
          • R Offline
            R Offline
            RickyRister
            wrote on last edited by RickyRister
            #9

            I tried to using QProxyStyle. It didn't work. My code is as follows

            // in the .h file
            class UnchangingCheckedButtonStyle : public QProxyStyle
            {
            public:
                void drawControl(ControlElement, const QStyleOption *, QPainter *, const QWidget * = nullptr) const;
            };
            
            // in the .cpp file
            void UnchangingCheckedButtonStyle::drawControl(ControlElement element,
                                                           const QStyleOption *option,
                                                           QPainter *painter,
                                                           const QWidget *widget) const
            {
                if (option->state & State_On){
                    QStyleOption *newOption = new QStyleOption(*option);
                    newOption->state.setFlag(State_On, false); 
                    QProxyStyle::drawControl(element, newOption, painter, widget);
                } else {
                    QProxyStyle::drawControl(element, option, painter, widget);
                }
            }
            
            // in the function for creating the button
            playButton = new QToolButton;
            QIcon icon = QIcon();
            icon.addPixmap(QPixmap("theme:replay/start"), QIcon::Normal, QIcon::Off);
            icon.addPixmap(QPixmap("theme:replay/pause"), QIcon::Normal, QIcon::On);
            playButton->setIcon(icon);
            playButton->setCheckable(true);
            auto style = new UnchangingCheckedButtonStyle();
            style->setParent(playButton);
            playButton->setStyle(style);
            

            The result is that the icon now disappears if the button is checked, but the button still darkens if checked! So seems like proxying the drawControl is in fact doing something, but whatever controls the color of the button when checked is not going through drawControl.

            Pl45m4P 1 Reply Last reply
            0
            • R RickyRister

              I tried to using QProxyStyle. It didn't work. My code is as follows

              // in the .h file
              class UnchangingCheckedButtonStyle : public QProxyStyle
              {
              public:
                  void drawControl(ControlElement, const QStyleOption *, QPainter *, const QWidget * = nullptr) const;
              };
              
              // in the .cpp file
              void UnchangingCheckedButtonStyle::drawControl(ControlElement element,
                                                             const QStyleOption *option,
                                                             QPainter *painter,
                                                             const QWidget *widget) const
              {
                  if (option->state & State_On){
                      QStyleOption *newOption = new QStyleOption(*option);
                      newOption->state.setFlag(State_On, false); 
                      QProxyStyle::drawControl(element, newOption, painter, widget);
                  } else {
                      QProxyStyle::drawControl(element, option, painter, widget);
                  }
              }
              
              // in the function for creating the button
              playButton = new QToolButton;
              QIcon icon = QIcon();
              icon.addPixmap(QPixmap("theme:replay/start"), QIcon::Normal, QIcon::Off);
              icon.addPixmap(QPixmap("theme:replay/pause"), QIcon::Normal, QIcon::On);
              playButton->setIcon(icon);
              playButton->setCheckable(true);
              auto style = new UnchangingCheckedButtonStyle();
              style->setParent(playButton);
              playButton->setStyle(style);
              

              The result is that the icon now disappears if the button is checked, but the button still darkens if checked! So seems like proxying the drawControl is in fact doing something, but whatever controls the color of the button when checked is not going through drawControl.

              Pl45m4P Offline
              Pl45m4P Offline
              Pl45m4
              wrote on last edited by
              #10

              @RickyRister said in How to stop a checkable button from automatically rendering differently when checked?:

              but whatever controls the color of the button when checked is not going through drawControl.

              You could check the source code of QAbstractButton / QToolButton yourself and see how it's done


              If debugging is the process of removing software bugs, then programming must be the process of putting them in.

              ~E. W. Dijkstra

              Christian EhrlicherC 1 Reply Last reply
              0
              • Pl45m4P Pl45m4

                @RickyRister said in How to stop a checkable button from automatically rendering differently when checked?:

                but whatever controls the color of the button when checked is not going through drawControl.

                You could check the source code of QAbstractButton / QToolButton yourself and see how it's done

                Christian EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #11

                @Pl45m4 said in How to stop a checkable button from automatically rendering differently when checked?:

                You could check the source code of QAbstractButton / QToolButton yourself and see how it's done

                Better the style he's using to see what triggers the darkening. Otoh when the style does this I don't understand why a QToolButton should behave differently only for his application.

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                1 Reply Last reply
                1
                • S Offline
                  S Offline
                  SimonSchroeder
                  wrote on last edited by
                  #12

                  First thing to check is to have drawControl just always forward to QProxyStyle. My guess is that this works.

                  What immediately caught my eye (but it is not your current problem) is that you leak the pointer to newOption. I would suggest that you just change the option you are given without making a copy.

                  Here is my best guess what's wrong: You do delete the QStyle::State_On flag. However, you didn't turn on the QStyle::State_Off flag. This might be the problem.

                  R 1 Reply Last reply
                  0
                  • S SimonSchroeder

                    First thing to check is to have drawControl just always forward to QProxyStyle. My guess is that this works.

                    What immediately caught my eye (but it is not your current problem) is that you leak the pointer to newOption. I would suggest that you just change the option you are given without making a copy.

                    Here is my best guess what's wrong: You do delete the QStyle::State_On flag. However, you didn't turn on the QStyle::State_Off flag. This might be the problem.

                    R Offline
                    R Offline
                    RickyRister
                    wrote on last edited by
                    #13

                    @SimonSchroeder

                    First thing to check is to have drawControl just always forward to QProxyStyle. My guess is that this works.

                    Yes, this indeed works

                    What immediately caught my eye (but it is not your current problem) is that you leak the pointer to newOption. I would suggest that you just change the option you are given without making a copy.

                    How would I go about doing this? I can't modify option directly because it's const.

                    Here is my best guess what's wrong: You do delete the QStyle::State_On flag. However, you didn't turn on the QStyle::State_Off flag. This might be the problem.

                    Tried toggling both flags. Same behavior (icon disappears but button still darkens)

                    void UnchangingCheckedButtonStyle::drawControl(ControlElement element,
                                                                   const QStyleOption *option,
                                                                   QPainter *painter,
                                                                   const QWidget *widget) const
                        {
                            if (option->state & State_On){
                                QStyleOption *newOption = new QStyleOption(*option);
                                newOption->state.setFlag(State_On, false); 
                                newOption->state.setFlag(State_Off, true); 
                                QProxyStyle::drawControl(element, newOption, painter, widget);
                            } else {
                                QProxyStyle::drawControl(element, option, painter, widget);
                            }
                        }
                    
                    S 1 Reply Last reply
                    0
                    • R RickyRister

                      @SimonSchroeder

                      First thing to check is to have drawControl just always forward to QProxyStyle. My guess is that this works.

                      Yes, this indeed works

                      What immediately caught my eye (but it is not your current problem) is that you leak the pointer to newOption. I would suggest that you just change the option you are given without making a copy.

                      How would I go about doing this? I can't modify option directly because it's const.

                      Here is my best guess what's wrong: You do delete the QStyle::State_On flag. However, you didn't turn on the QStyle::State_Off flag. This might be the problem.

                      Tried toggling both flags. Same behavior (icon disappears but button still darkens)

                      void UnchangingCheckedButtonStyle::drawControl(ControlElement element,
                                                                     const QStyleOption *option,
                                                                     QPainter *painter,
                                                                     const QWidget *widget) const
                          {
                              if (option->state & State_On){
                                  QStyleOption *newOption = new QStyleOption(*option);
                                  newOption->state.setFlag(State_On, false); 
                                  newOption->state.setFlag(State_Off, true); 
                                  QProxyStyle::drawControl(element, newOption, painter, widget);
                              } else {
                                  QProxyStyle::drawControl(element, option, painter, widget);
                              }
                          }
                      
                      S Offline
                      S Offline
                      SimonSchroeder
                      wrote on last edited by
                      #14

                      @RickyRister said in How to stop a checkable button from automatically rendering differently when checked?:

                      How would I go about doing this? I can't modify option directly because it's const.

                      Alright, I didn't see that it is const. Still, you can just use a local variable:

                      QStyleOption newOption = *option;
                      ...
                      QProxyStyle::drawControl(element, &newOption, painter, widget);
                      

                      @RickyRister said in How to stop a checkable button from automatically rendering differently when checked?:

                      Tried toggling both flags. Same behavior (icon disappears but button still darkens)

                      I did some more reading of the documentation for QStyle::DrawControl. It says the following:

                      The option parameter is a pointer to a QStyleOption object that can be cast to the correct subclass using the qstyleoption_cast() function.

                      Further down, it says in the table that the correct style option seems to be a QStyleOptionToolButton. So, just copying the option variable will splice the object, i.e. it will only copy the information that is contained in the QStyleOption class, but will ommit everything that has been inherited. My guess (I haven't tried it myself) is to do the following instead:

                      QStyleOptionToolButton newOption = *qstyleoption_cast<const QStyleOptionToolButton *>(option);
                      
                      R 1 Reply Last reply
                      0
                      • S SimonSchroeder

                        @RickyRister said in How to stop a checkable button from automatically rendering differently when checked?:

                        How would I go about doing this? I can't modify option directly because it's const.

                        Alright, I didn't see that it is const. Still, you can just use a local variable:

                        QStyleOption newOption = *option;
                        ...
                        QProxyStyle::drawControl(element, &newOption, painter, widget);
                        

                        @RickyRister said in How to stop a checkable button from automatically rendering differently when checked?:

                        Tried toggling both flags. Same behavior (icon disappears but button still darkens)

                        I did some more reading of the documentation for QStyle::DrawControl. It says the following:

                        The option parameter is a pointer to a QStyleOption object that can be cast to the correct subclass using the qstyleoption_cast() function.

                        Further down, it says in the table that the correct style option seems to be a QStyleOptionToolButton. So, just copying the option variable will splice the object, i.e. it will only copy the information that is contained in the QStyleOption class, but will ommit everything that has been inherited. My guess (I haven't tried it myself) is to do the following instead:

                        QStyleOptionToolButton newOption = *qstyleoption_cast<const QStyleOptionToolButton *>(option);
                        
                        R Offline
                        R Offline
                        RickyRister
                        wrote on last edited by RickyRister
                        #15

                        @SimonSchroeder

                        Alright, I didn't see that it is const. Still, you can just use a local variable

                        Good catch

                        Further down, it says in the table that the correct style option seems to be a QStyleOptionToolButton. So, just copying the option variable will splice the object, i.e. it will only copy the information that is contained in the QStyleOption class, but will ommit everything that has been inherited. My guess (I haven't tried it myself) is to do the following instead:

                        QStyleOptionToolButton newOption = *qstyleoption_cast<const QStyleOptionToolButton *>(option);
                        

                        Making this change did cause something to change! The icon no longer disappears when checked; it will stay the same instead. ...The button still darkens though.

                        At this point, I'm starting to suspect that the button color is solely controlled through the stylesheet, and that the stylesheet bypasses drawControl.

                        Christian EhrlicherC S 2 Replies Last reply
                        0
                        • R RickyRister

                          @SimonSchroeder

                          Alright, I didn't see that it is const. Still, you can just use a local variable

                          Good catch

                          Further down, it says in the table that the correct style option seems to be a QStyleOptionToolButton. So, just copying the option variable will splice the object, i.e. it will only copy the information that is contained in the QStyleOption class, but will ommit everything that has been inherited. My guess (I haven't tried it myself) is to do the following instead:

                          QStyleOptionToolButton newOption = *qstyleoption_cast<const QStyleOptionToolButton *>(option);
                          

                          Making this change did cause something to change! The icon no longer disappears when checked; it will stay the same instead. ...The button still darkens though.

                          At this point, I'm starting to suspect that the button color is solely controlled through the stylesheet, and that the stylesheet bypasses drawControl.

                          Christian EhrlicherC Offline
                          Christian EhrlicherC Offline
                          Christian Ehrlicher
                          Lifetime Qt Champion
                          wrote on last edited by
                          #16

                          @RickyRister said in How to stop a checkable button from automatically rendering differently when checked?:

                          the stylesheet

                          You are funny - giving such an important information after five days... and not even showing us the stylesheet you're using.
                          As I already wrote - directly look in the style code instead guessing five days.

                          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                          Visit the Qt Academy at https://academy.qt.io/catalog

                          R 1 Reply Last reply
                          2
                          • Christian EhrlicherC Christian Ehrlicher

                            @RickyRister said in How to stop a checkable button from automatically rendering differently when checked?:

                            the stylesheet

                            You are funny - giving such an important information after five days... and not even showing us the stylesheet you're using.
                            As I already wrote - directly look in the style code instead guessing five days.

                            R Offline
                            R Offline
                            RickyRister
                            wrote on last edited by RickyRister
                            #17

                            @Christian-Ehrlicher

                            The app doesn't set a stylesheet by default, so it's just using the default style for whatever OS it's on. Which apparently just gives me an empty string if I call app.stylesheet().

                            1 Reply Last reply
                            0
                            • R RickyRister

                              @SimonSchroeder

                              Alright, I didn't see that it is const. Still, you can just use a local variable

                              Good catch

                              Further down, it says in the table that the correct style option seems to be a QStyleOptionToolButton. So, just copying the option variable will splice the object, i.e. it will only copy the information that is contained in the QStyleOption class, but will ommit everything that has been inherited. My guess (I haven't tried it myself) is to do the following instead:

                              QStyleOptionToolButton newOption = *qstyleoption_cast<const QStyleOptionToolButton *>(option);
                              

                              Making this change did cause something to change! The icon no longer disappears when checked; it will stay the same instead. ...The button still darkens though.

                              At this point, I'm starting to suspect that the button color is solely controlled through the stylesheet, and that the stylesheet bypasses drawControl.

                              S Offline
                              S Offline
                              SimonSchroeder
                              wrote on last edited by
                              #18

                              @RickyRister said in How to stop a checkable button from automatically rendering differently when checked?:

                              The icon no longer disappears when checked; it will stay the same instead.

                              This is not totally unexpected: You say that the style should draw the tool button in the on state, so it does (meaning it uses the icon for the on state). You also get handed in a QWidget pointer which should be the QToolButton. You could make a copy of this and change the icon for the on state to that of the off state and render that.

                              I'm out of ideas why it is still drawn dark. Maybe you can check which style options are actually set. Have a look at the options for the regular on state and the off state (and also post them). There might be yet another difference besides State_On/State_Off.

                              1 Reply Last reply
                              0

                              • Login

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