Search code examples
qttooltipqtoolbar

Show shortcut in tooltip of QToolBar


I have QActions added to a QToolBar using addAction().

I want the toolbar button tooltips to show the shortcuts. e.g. Copy (Ctrl+C). Of course, i could statically set

action->setTooltip(QString("%1 (%2)").arg(action.toolTip(), action->shortcut().toString(QKeySequence::NativeText)));

However, this is quite cumbersome because there are lots of actions and the user can modify the shortcuts so that I would have to keep track of that and update accordingly. It would be much nicer if I could simply modify the QToolBar tooltip behavior by subclassing QToolBar similar to http://doc.qt.io/qt-5/qtwidgets-widgets-tooltips-example.html.

Unfortunately, it's not that simple. The tooltip is not generated by the QToolBar itself, but apparently by a QToolButton which is created internally when using addAction(). So ideally I would inject my own subclass of QToolButton. But that seems imposible because the actual instantiation of the toolbutton is done inside the private QToolBarLayout which I cannot access.

Any ideas how to solve this?


Solution

  • I've not been able to find a solution by subclassing QToolBar or anything related. Therefore I have resorted to overwrite the tooltip of the QAction. This is what it looks like in the end:

    example

    I've written functions to add/remove the shorcut information, so that the changes are reversible (e.g. required if the behavior should be switchable). If removal is not needed, addShortcutToToolTip() can be simplified a bit.

    /* guesses a descriptive text from a text suited for a menu entry
       This is equivalent to QActions internal qt_strippedText()
    */
    static QString strippedActionText(QString s) {
        s.remove( QString::fromLatin1("...") );
        for (int i = 0; i < s.size(); ++i) {
            if (s.at(i) == QLatin1Char('&'))
            s.remove(i, 1);
        }
        return s.trimmed();
    }
    
    
    /* Adds possible shortcut information to the tooltip of the action.
       This provides consistent behavior both with default and custom tooltips
       when used in combination with removeShortcutToToolTip()
    */
    void addShortcutToToolTip(QAction *action)
    {
        if (!action->shortcut().isEmpty()) {
            QString tooltip = action->property("tooltipBackup").toString();
            if (tooltip.isEmpty()) {
                tooltip = action->toolTip();
                if (tooltip != strippedActionText(action->text())) {
                    action->setProperty("tooltipBackup", action->toolTip());  // action uses a custom tooltip. Backup so that we can restore it later.
                }
            }
            QColor shortcutTextColor = QApplication::palette().color(QPalette::ToolTipText);
            QString shortCutTextColorName;
            if (shortcutTextColor.value() == 0) {
                shortCutTextColorName = "gray";  // special handling for black because lighter() does not work there [QTBUG-9343].
            } else {
                int factor = (shortcutTextColor.value() < 128) ? 150 : 50;
                shortCutTextColorName = shortcutTextColor.lighter(factor).name();
            }
            action->setToolTip(QString("<p style='white-space:pre'>%1&nbsp;&nbsp;<code style='color:%2; font-size:small'>%3</code></p>")
                               .arg(tooltip, shortCutTextColorName, action->shortcut().toString(QKeySequence::NativeText)));
        }
    }
    
    
    /* Removes possible shortcut information from the tooltip of the action.
       This provides consistent behavior both with default and custom tooltips
       when used in combination with addShortcutToToolTip()
    */
    void removeShortcutFromToolTip(QAction *action)
    {
        action->setToolTip(action->property("tooltipBackup").toString());
        action->setProperty("tooltipBackup", QVariant());
    }