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.
  • JonBJ JonB

    @RickyRister
    I have not done this, but here is my understanding. Although you do not say, I presume you have used a QIcon for the icon of the QToolButton.

    A tool button's icon is set as QIcon. This makes it possible to specify different pixmaps for the disabled and active state. The disabled pixmap is used when the button's functionality is not available. The active pixmap is displayed when the button is auto-raised because the mouse pointer is hovering over it.

    QIcons have a number of different modes/states. Look at https://doc.qt.io/qt-6/qicon.html#making-classes-that-use-qicon where these are shown. I think your case is the bottom right one, On and Selected?

    So you want to alter that. I guess either you call void QIcon::addPixmap(const QPixmap &pixmap, QIcon::Mode mode = Normal, QIcon::State state = Off) to explicitly add your desired pixmap without the "darkening" for the mode/state you want to change or you cause it to draw/paint as QIcon::Off when asked to draw it QIcon::On.

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

    @JonB
    Yes, I am using a QIcon. This is my code currently

    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);
    

    The icon displayed on the button correctly changes to match the state. However, when the button is checked, it is darkened in addition to changing the icon. I would like to make it so that only the icon changes when the button is checked, without the button also darkening.

    JonBJ 1 Reply Last reply
    0
    • R RickyRister

      @JonB
      Yes, I am using a QIcon. This is my code currently

      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);
      

      The icon displayed on the button correctly changes to match the state. However, when the button is checked, it is darkened in addition to changing the icon. I would like to make it so that only the icon changes when the button is checked, without the button also darkening.

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #4

      @RickyRister
      I can only guess. Did you look at https://doc.qt.io/qt-6/qicon.html#making-classes-that-use-qicon as I suggested? The only ones there I can see "darkened", excluding Disabled, is Selected. Is your checked icon darkened because/only while it is selected? Did you try addPixmap(..., QIcon::Selected, QIcon::On)?

      1 Reply Last reply
      0
      • 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 Online
                    Christian EhrlicherC Online
                    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 Online
                              Christian EhrlicherC Online
                              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