【问题标题】:How to add an icon to a QGroupBox title?如何将图标添加到 QGroupBox 标题?
【发布时间】:2019-03-08 15:08:57
【问题描述】:

是否可以向 QGroupBox 标题添加图标(以编程方式,通过 QtCreator,带有或不带有样式表)?

我想在我的 GUI 中一些 QGroupBoxes 的标题附近放置一个标记。最好的位置是在标题的右侧,但任何其他合理的位置(在标题的左侧,或在小部件的右上角)也可以是有效的。

我能想到的唯一方法是创建一个带有图标的 QLabel,并将其直观地放置在 QGroupBox 顶部所需的位置。但我觉得这是一个丑陋的解决方案。

编辑

我知道有一种方法可以使用样式表将用于checkable QGroupBoxes 的indicator 设置为任何图像,无论是选中状态还是未选中状态。但是 QGroupBox 必须是可检查的,等等。我想将这个标记(一个小图像)独立添加到 QGroupBox 的 checkability 中。

【问题讨论】:

  • 我要打个标记你的意思是打勾吗?
  • 不,抱歉。我的意思是一些小图像。举个例子:如果我没有办法做到这一点,最后我会在标题末尾附加一个星号(*)......但我希望有可能添加任何小图像(一个蓝点、一颗红钻石、一颗绿星……)
  • 我明白了。因为复选标记很容易添加。图像已经是一个挑战。但我正在努力,我希望我能尽快给你一个解决方案。
  • 请看一下this result,让我知道它是否适合您。如果您想以某种方式对其进行调整,请告诉我,我会为您做。然后我会发布解决方案。
  • 看起来很有希望!那当然适合我!

标签: c++ qt


【解决方案1】:

背景

不幸的是,QGroupBox 没有 setIcon 方法,就像 QPushButton 一样。

一种可能的解决方案是使用QGroupBox::setCheckable 使QGroupBox 可检查,并使用stylesheet 将自定义图像设置为指示器,如下所示:

QGroupBox::indicator:unchecked {
    image: url(:/images/checkbox_unchecked.png);
}

但是,当复选框未选中时,这将禁用整个组框。

解决方案

考虑到这一背景,我建议您使用一个相当复杂但也非常灵活的解决方案,包括以下步骤:

  1. 子类QStyleOptionGroupBox并将附加变量声明为公共类属性:

    QPixmap pixmap;
    int offset;
    int leftSpace;
    int rightSpace;
    

    这些将用于将装饰像素图以及放置设置传递给样式。

  2. 子类QCommonStyle 并像这样重新实现QCommonStyle::drawComplexControl

    if (const StyleOptionDecoratedGroupBox *groupBox = qstyleoption_cast<const StyleOptionDecoratedGroupBox *>(opt)) {
        QRect textRect = proxy()->subControlRect(CC_GroupBox, opt, SC_GroupBoxLabel, widget);
        QRect checkBoxRect = proxy()->subControlRect(CC_GroupBox, opt, SC_GroupBoxCheckBox, widget);
        int decorationOffset = 0;
        int pixmapRectWidth = 0;
        int pixmapHeight = 0;
        int textOffset = 0;
    
        if (!groupBox->pixmap.isNull()) {
            decorationOffset = groupBox->offset;
            pixmapRectWidth = groupBox->leftSpace
                            + groupBox->pixmap.width()
                            + groupBox->rightSpace;
            pixmapHeight = groupBox->pixmap.height();
            textOffset = decorationOffset + pixmapRectWidth;
        }
    
        textRect.adjust(textOffset, 0, textOffset, 0);
    
        // Draw frame
        if (groupBox->subControls & QStyle::SC_GroupBoxFrame) {
            QStyleOptionFrame frame;
            frame.QStyleOption::operator=(*groupBox);
            frame.features = groupBox->features;
            frame.lineWidth = groupBox->lineWidth;
            frame.midLineWidth = groupBox->midLineWidth;
            frame.rect = proxy()->subControlRect(CC_GroupBox, opt, SC_GroupBoxFrame, widget);
            p->save();
            QRegion region(groupBox->rect);
            if (!groupBox->text.isEmpty()) {
                bool ltr = groupBox->direction == Qt::LeftToRight;
                QRect finalRect;
                if (groupBox->subControls & QStyle::SC_GroupBoxCheckBox) {
                    finalRect = checkBoxRect.united(textRect);
                    finalRect.adjust(ltr ? -4 : 0, 0, ltr ? 0 : 4, 0);
                } else {
                    finalRect = textRect;
                }
                region -= finalRect;
            }
            p->setClipRegion(region);
            proxy()->drawPrimitive(PE_FrameGroupBox, &frame, p, widget);
            p->restore();
        }
    
        // Draw icon
        if (!groupBox->pixmap.isNull()) {
            p->fillRect(decorationOffset, 0, pixmapRectWidth, pixmapHeight, opt->palette.window().color());
            proxy()->drawItemPixmap(p, QRect(decorationOffset, 0, pixmapRectWidth, pixmapHeight),
                                    Qt::AlignCenter, groupBox->pixmap);
        }
    
        // Draw title
        if ((groupBox->subControls & QStyle::SC_GroupBoxLabel) && !groupBox->text.isEmpty()) {
            QColor textColor = groupBox->textColor;
            if (textColor.isValid())
                p->setPen(textColor);
            int alignment = int(groupBox->textAlignment);
            if (!proxy()->styleHint(QStyle::SH_UnderlineShortcut, opt, widget))
                alignment |= Qt::TextHideMnemonic;
            proxy()->drawItemText(p, textRect,  Qt::TextShowMnemonic | Qt::AlignHCenter | alignment,
                                  groupBox->palette, groupBox->state & State_Enabled, groupBox->text,
                                  textColor.isValid() ? QPalette::NoRole : QPalette::WindowText);
            if (groupBox->state & State_HasFocus) {
                QStyleOptionFocusRect fropt;
                fropt.QStyleOption::operator=(*groupBox);
                fropt.rect = textRect;
                proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p, widget);
            }
        }
    } else {
        QCommonStyle::drawComplexControl(cc, opt, p, widget);
    }
    
  3. 子类QGroupBox 并像这样重新实现QGroupBox::paintEvent

    CustomStyle style;
    QPainter painter(this);
    StyleOptionDecoratedGroupBox option;
    
    initStyleOption(&option);
    option.pixmap = m_pixmap;
    option.offset = m_offset;
    option.leftSpace = m_leftSpace;
    option.rightSpace = m_rightSpace;
    
    style.drawComplexControl(QStyle::CC_GroupBox, &option, &painter, this);
    

注意:此方案在分组框可勾选时效果不佳。

示例

解决方案需要大量工作,但幸运的是我已经为您创建了必要的类,以及如何在您自己的项目中使用它们的完整示例。代码在GitHub 上提供。

结果

提供的示例产生以下结果:

【讨论】:

  • 从如此简单的起点出发,这是一个相当全面的答案——出色的工作!
  • 谢谢你,@TobySpeight!对此,我真的非常感激!这似乎是一项直接的任务,但我最终挖掘了三个 Qt 类的代码。 :) 我真的希望这将为那些想要达到相同效果的人节省一些工作。
  • 这个解决方案简直太棒了!!非常感谢你的努力!!
  • 你得到了我的支持,但我仍然有一个小批评:你没有编辑图片链接的替代文本。由于我公司的防火墙阻止了 imgur.com(而且我无法说服管理员取消阻止),我总是看到这些 在此处输入图像描述 链接。这有点烦人... ;-) (当我几十年前学习 HTML 时,这是基本建议之一:始终为图像提供替代文本 - 现在似乎完全忘记了。)
  • @Scheff,我非常感谢您的批评。事实上,[qt] 标签描述中说:我们的目标是在这个标签中实现高质量。所以,因为卓越在于细节,所以没有细节是小到可以不加以改进的。在您发表评论后,我在大多数答案的图像中添加了描述。稍后我将编辑其余部分。谢谢你提醒我!
猜你喜欢
  • 2019-09-03
  • 1970-01-01
  • 1970-01-01
  • 2020-11-28
  • 1970-01-01
  • 1970-01-01
  • 2011-09-18
  • 1970-01-01
相关资源
最近更新 更多