1

In my project I display a QMenu with several QAction objects. I want the QAction icon to change when the user hovers over it.

Here is my current code:

QPixmap icons(":/icons/platformIcons.png");

QIcon icon;
icon.addPixmap(icons.copy(0, 0, 16, 16), QIcon::Selected, QIcon::On);
icon.addPixmap(icons.copy(0, 16, 16, 16), QIcon::Selected, QIcon::Off);

ui->actionOpen->setIcon(icon);

However the icon doesn't change when the user hovers over the QAction. I've tried modes Normal and Active and the result is the same. If I switch the states, the icon is reversed, but still doesn't change on a hover (or click for that matter).

Thanks for your time.

mrg95
  • 2,371
  • 11
  • 46
  • 89

1 Answers1

0

Support for hovering normal/active icons in menus and toolbars seems to depend on the platform style, and is not supported with native Mac styling in particular, even when disabling usage of the native menu bar (ie. having the menus show at the top of the desktop rather than within the application window).

I've made a quick try with a Qt Designer form on a Mac to replicate your use case (basically ends up as the same C++ code using QIcon::addPixmap()):

?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget"/>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>400</width>
     <height>22</height>
    </rect>
   </property>
   <property name="nativeMenuBar">
    <bool>false</bool>
   </property>
   <widget class="QMenu" name="menuYo">
    <property name="title">
     <string>Yo</string>
    </property>
    <addaction name="actionFoo"/>
    <addaction name="actionBar"/>
   </widget>
   <addaction name="menuYo"/>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
   <addaction name="actionFoo"/>
   <addaction name="actionBar"/>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
  <action name="actionFoo">
   <property name="checkable">
    <bool>true</bool>
   </property>
   <property name="icon">
    <iconset>
     <normaloff>../red-circle.png</normaloff>
     <normalon>../greeb-circle.png</normalon>
     <activeoff>../red-square.png</activeoff>
     <activeon>../green-square.png</activeon>../red-circle.png</iconset>
   </property>
   <property name="text">
    <string>Foo</string>
   </property>
  </action>
  <action name="actionBar">
   <property name="text">
    <string>Bar</string>
   </property>
  </action>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

When using the default Mac styling, I only get the red/green circle icon in the menu and the toolbar, even when hovering the mouse. However if I force another style with e.g. ui->menuYo->setStyle(QStyleFactory::create("fusion")); then the hovering works, but the menu doesn't look native anymore...

Romain Pokrzywka
  • 200
  • 1
  • 12
  • I'm not using a Mac and neither will my users. Windows only. Should I expect it to work on Windows with the way I've done it? Also, my images are derived from one big image, so using Qt Designer isn't gonna work for my use case. – mrg95 Dec 22 '16 at 08:00
  • 1
    I don't have a Windows machine handy so I can't tell you for sure if it will work with the native styling. But at least based on your approach it should work. Just be aware that `QIcon::Selected` doesn't apply to menus. What you want is `QIcon::Normal` (== unhovered) and `QIcon::Active` (== hovered), while `QIcon::Off` and `QIcon::On` only apply to checkable actions (ie. that have a checked/unchecked state). One way to test if it's your code or the style is to run the app with the argument `-style fusion` which uses the Fusion widget style. That one is guaranteed to work if the code is right – Romain Pokrzywka Dec 22 '16 at 09:27
  • AH! The issue was that I needed to set both states to `QIcon::Off`. I didn't realize it had to do with being checked or not. Thanks :) – mrg95 Dec 22 '16 at 10:05