Can Checkable QActions (menu items) with Icons also show check indicators?
-
I'm finding that adding an icon to a checkable QAction prevents the check indicator from showing up (i.e. on the QAction's menu item in a menu). Is there a way of showing both an icon and a check indicator on a checkable QAction? (Thanks, everyone, in advance).
See the accompanying image and code excerpt. We're using Qt 4.8.5 on Windows.
!http://cadswes2.colorado.edu/~philw/2013/icons/WindowIcon/WinIconMenu1-Detail.png(Checkable QAction with icon doesn't show check indicator)!
@void IconUtils::addWindowIconActions (QMenu* parMenu, QActionGroup* actGrp)
{
actGrp->setExclusive (true);const QStringList iconNames = windowIconNames();
const int cnt = iconNames.count();for (int inx = 0; inx < cnt; ++inx)
{
const QString iconName = iconNames [inx];QAction* winIconAction = new QAction (actGrp); winIconAction -> setObjectName (iconName); winIconAction -> setIcon (windowIconPixmap (iconName)); winIconAction -> setData (QVariant (inx)); winIconAction -> setCheckable (true); winIconAction -> setChecked (inx == 0); parMenu->addAction (winIconAction);
}
}@ -
By the way, I did experiment will all widget styles available in our Qt 4.8.5 build on Windows 7. They all exhibited this problem. Here are some screenshots ... animated and montage:
!http://cadswes2.colorado.edu/~philw/2013/icons/WindowIcon/DetailB-Anim.gif(Animated GIF, 7 widget styles compared)!
!http://cadswes2.colorado.edu/~philw/2013/icons/WindowIcon/DetailB-Montage.png(Montage, 7 widget styles compared)!
Any ideas on how to get the check indicator to show up?
-
AFAIK you can't have both. Either you set an icon or an checkbox.
This isn't a Qt bug IMHO, take other application's (native looking) menus as reference for example. -
Raven-worx, thanks for your note. I can see that this probably WAS the intended appearance. I'm now noticing that the "ON" item is indicated with the active Icon state. It's subtle.
Still though, we really want a clear check indicator on the selected item. I'll try to get a "bullet" in there, dynamically building hybrid QPixmaps ... and I have my fingers crossed that I can get a rectangular (non-square) QAction (menu item) icon displayed with "QProxyStyle":http://qt-project.org/doc/qt-4.8/qproxystyle.html and "QStyle::PM_SmallIconSize":http://qt-project.org/doc/qt-4.8/qstyle.html#PixelMetric-enum for the extra icon width. (That really looks like it wants to be square).
-
I DID ACCOMPLISH THIS -- showing a CHECK INDICATOR (exclusive, radio-button type) on checkable QAction menu items having Icons. I'm creating the check indicator graphic myself -- augmenting the application-level icon QPixmaps. BELOW are the three pieces of code which implement this. SEE RESULT EXAMPLE:
!http://cadswes2.colorado.edu/~philw/2013/icons/WindowIcon/2013-10-07a.png(success)!
CODE SAMPLES BELOW:
#1 class QMenuIconSizeProxyStyle : public QProxyStyle
... allows a QMenu to have wider-than-normal icons on menu items (QActions).#2 QIcon checkMenuIcon (const QPixmap& sourcePmap, QSize& iconSize)
... Create a two-state QIcon from a source QPixmap, adding on a check indicator graphic#3 void addWindowIconActions (QMenu* menu, QActionGroup* actGrp)
... builds a menu of exclusive items for a list of application-level icons. (uses both items above).@// QProxyStyle sublass to be installed on a QMenu needing to support
// wider-than-usual icons. It overrides the QStyle::PM_SmallIconSize
// property with the width of the QSize provided by the client.class QMenuIconSizeProxyStyle : public QProxyStyle
{
private:
QSize _iconSize; // note: only the width is currently used.public:
QMenuIconSizeProxyStyle() : QProxyStyle() {}void setIconSize (const QSize& iconSize) { _iconSize = iconSize; }
int pixelMetric (QStyle::PixelMetric metric,
const QStyleOption* option=NULL,
const QWidget* widget=NULL) const override
{
if (metric == QStyle::PM_SmallIconSize)
return (_iconSize.width());// Return base class result return QProxyStyle::pixelMetric (metric, option, widget);
}
};@@QIcon checkMenuIcon (const QPixmap& sourcePmap, QSize& iconSize)
{
// Create and return a QIcon composed from two modified versions of
// the given "source" QPixmap -- for ON and OFF states -- suitable for
// checkable QActions (menu items) having an icon. [In Qt 4.8.5,
// checkable QActions with icons don't show a drawn check indicator].
//
// The computed pixmaps have additional space to the left where a
// bullet (filled black circle) is drawn on the "ON" image. This
// appearance is intended for exclusive (radio button type)
// QActions (menu items) -- and looks like the Cleanlooks style.
//
// The QSize of the computed pixmaps (including a check indicator area)
// is returned in the iconSize reference parameter.const QSize srcSize = sourcePmap.size();
const int srcWid = srcSize.width();
const int srcHgt = srcSize.height();
const int indWid = srcHgt; // indicator widthiconSize = QSize (srcWid + indWid, srcHgt);
QPixmap iconPmap (iconSize);
iconPmap.fill (Qt::transparent);QPainter painter (&iconPmap);
painter.drawPixmap (indWid, 0, sourcePmap);QIcon retIcon;
retIcon.addPixmap (iconPmap, QIcon::Normal, QIcon::Off);const double radius (indWid / 8.0);
const QPointF cen (indWid/2.0, srcHgt/2.0);
painter.setBrush (QBrush (Qt::black));
painter.drawEllipse (cen, radius, radius);retIcon.addPixmap (iconPmap, QIcon::Normal, QIcon::On);
return (retIcon);
}@@// Build a QMenu with checkable (mutually exclusive) icon QActions.
// The 'checkMenuIcon' utility is used to add a "radio button"-type
// check indicator to the left of each source QPixmap.void addWindowIconActions (QMenu* menu, QActionGroup* actGrp)
{
actGrp->setExclusive (true);
QSize maxIconSize;// Create a checkable Icon QAction (menu item) for each available
// application window icon; insert into the given QMenu and QActionGroup.const QStringList iconNames = windowIconNames();
const int cnt = iconNames.count();for (int inx = 0; inx < cnt; ++inx)
{
const QString iconName = iconNames [inx];QSize iconSize; const QPixmap pmap = windowIconPixmap (iconName); const QIcon menuIcon = checkMenuIcon (pmap, iconSize); // SEE ABOVE maxIconSize = maxIconSize.expandedTo (iconSize); QAction* winIconAction = new QAction (actGrp); winIconAction -> setObjectName (iconName); winIconAction -> setIcon (menuIcon); winIconAction -> setData (QVariant (inx)); winIconAction -> setCheckable (true); winIconAction -> setChecked (false); menu->addAction (winIconAction);
}
// Instantiate a QProxyStyle for a modified QStyle::PM_SmallIconSize
// and install that on the QMenu. SEE PRIOR FUNCTION.QMenuIconSizeProxyStyle* proxyStyle = new QMenuIconSizeProxyStyle;
proxyStyle->setIconSize (maxIconSize);
menu->setStyle (proxyStyle);
}@