Merge two QIcon

Viewed 794

QIcon has a notion of state, e.g. when requesting a pixmap from a QIcon one can ask it for a pixmap for an On state (like a depressed push button) or in an Off state.

Creating a state-aware QIcon is straightforward: Just call the QIcon::addPixmap() member function with a suitable combination of the mode and state arguments to compose the desired pixmaps into the QIcon.

When using Qt's theme mechanism, however, one creates the QIcon using the QIcon::fromTheme() static member function. The icons returned by this function are not state-aware. In fact, from the Qt sources I learnt that only the QIcon::Mode is applied on the fly, e.g. to gray out the icon for a Disabled mode.

So consider I create two distinct icons from the theme, onIcon and offIcon, how could I merge them into a single QIcon to cover the respective States?

1 Answers

The trick is to use the QIcon::availableSizes to extract all the individual pixmaps from each icon, and then assign a role (mode + state) to each set.

Here a basic example with just on and off states.

QIcon mergeIcons(const QIcon& on_icon, const QIcon& off_icon) {
  QIcon new_icon;
  const auto fn_add = [&new_icon](const QIcon& src, QIcon::Mode mode, QIcon::State state) {
    const auto sizes = src.availableSizes();
    for (const auto& size : sizes) {
      new_icon.addPixmap(src.pixmap(size), mode, state);
    }      
  };

  fn_add(on_icon, QIcon::Normal, QIcon::On);
  fn_add(off_icon, QIcon::Normal, QIcon::Off);

  return new_icon;
}

Then simply load the source icons and merge them:

const QIcon on_icon("on.ico");
const QIcon off_icon("off.ico");
ui->pushButton->setIcon(mergeIcons(on_icon, off_icon));
Related