Search code examples
c++qtqt5qtstylesheetsqtoolbar

How to change the icon of a QAction on a QToolBar when checked/unchecked?


I've created a QToolBar:

QToolBar* pQToolbar = new QToolBar();
QAction* pAction = pQToolbar->addAction("CoordinateType");
pAction->setObjectName("CoordinateType");
pAction->setIcon(QIcon("global.png"));
pAction->setCheckable(true);

Then I tried to set the icon when checked in the stylesheet:

#CoordinateType {
    image: url(global.png);
}

#CoordinateType:checked {
    image: url(local.png);
}

But it doesn't work.

So what should I do to change the icon when the tool button is checked?


Solution

  • Cause

    There are a couple of problems with your approach:

    1. You set the object name of the action. The action itself is not stylable. It is assigned to a button and its name is not transfered to this button (since a button might have several actions assigned to it). Thus your selector #CoordinateType won't work and you won't be able to target this particular button.

    2. It is not possible to set the icon of a QToolButton using the image property, as the stylesheet reference states:

    The image that is drawn in the contents rectangle of a subcontrol.

    If you want to set an image on a button, use background-image instead. Setting the following qss as a global stylesheet works to some extent, but again, it is difficult to target a particular button of QToolBar:

    QToolButton {
        background-image: url(global.png);
    }
    
    QToolButton:checked {
        background-image: url(local.png);
    }
    

    Solution

    Considering the mentioned problems, my solution would be to use QIcon::State instead of a stylesheet.

    Example

    Here is an example of how to change your code to achieve that:

    1. Create an icon and set it up

      QIcon icon;
      
      icon.addPixmap(QPixmap("global.png"), QIcon::Normal, QIcon::Off);
      icon.addPixmap(QPixmap("local.png"), QIcon::Normal, QIcon::On);
      
    2. Set the icon as pAction's icon

      pAction->setIcon(icon);
      

    Note: It is possible, that you have to consider the other modes too.