Tim Hoffmann
Tim Hoffmann

Reputation: 1345

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?

Upvotes: 4

Views: 1603

Answers (1)

Tim Hoffmann
Tim Hoffmann

Reputation: 1345

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());
}

Upvotes: 5

Related Questions