当前位置:   article > 正文

Qt中QComboBox下拉列表(popup)位置与样式的控制_qt combobox-popup

qt combobox-popup

转载请注明来源:http://blog.csdn.net/imred
Qt中的QComboBox在不同平台下有所差异(主要是不可编辑的QComboBox),如下样式A和样式B:
样式A样式B
左边为样式A为“fusion”样式,在ubuntu下的样式似乎就是这个,它的特点是下拉列表会把文字框和箭头盖住。右边样式B为“windowsvista”样式,它是win10下Qt的默认样式,其特点是下拉列表会显示在文字框和箭头下方,所以不会盖住文字框和箭头。
那么如何在不改变全局样式(即指定“fusion”样式或“windowsvista”样式)的情况下对QComboBox的样式进行控制,使其显示为样式A或样式B呢?如果全局样式使得QComboBox为样式A,而你想使用样式B,这种情况是比较简单的,使用qss即可满足需求,对QComboBox调用setStyleSheet(“QComboBox {combobox-popup: 0;}”)后,样式就变成了这样:
样式C
虽然和样式B不完全一样,但再使用qss对文字框和箭头样式微调一下就可以达到和样式B差不多的效果。
而如果全局样式是样式B,想要把QComboBox改成样式A,那就要费一番周折了,当然了,如果你看到了我这篇博客,就不用费那么多周折了。
首先,类似地,我们对QComboBox对象调用setStyleSheet,这里将combobox-popup设为1,得到了如下样式:
样式D
每一项左边空出了一大块空白,被选中的项还多了一个对勾图标。如果你对这种样式还算满意的话,就不用往下看了。如果不满意的话,我们还要想办法调整一下样式。
我一开始想要使用qss来进行调整,然而死活调不动,最多也就能调整一下文字的颜色和背景色啥的,调整大小时要么调不了,要么各种错位,想要调整图标,更是根本没找到方法。
那么该如何调整呢,答案是使用QStyle类来控制样式,这个类可以精确的控制每个控件该如何绘制。各个平台下默认样式不同,实际上就是因为不同平台下默认使用了不同的QStyle类的派生类,如qfusionstyle.cpp、qwindowsstyle.cpp等,不过这些类我们是不能直接使用的,只能使用setStyle(“fusion”)这样的方式,如果我们自己实现了一个QStyle派生类,则可以使用setStyle(new MyStyle)这样的方式来直接使用我们的类。
我们需要做的就是实现一个自己的QStyle类,这个类相当复杂,就不介绍了,我们需要做的就是重新实现它的drawControl方法。一般在实现自己的样式时,是不会去继承QStyle类的,它是一个纯虚类,如果你要继承它的话,需要实现所有的方法。一般都是继承QProxyStyle类,这个类的样式一般就是当前平台下的默认样式。对于我们想要控制的内容,我们自己实现,对于不想控制的内容,直接使用父类的方法(即QProxyStyle类)就可以了。
drawControl方法的函数签名如下:

void QProxyStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = Q_NULLPTR) const
  • 1

当绘制一个元素时,就会调用这个方法(不是所有元素都会调用这个方法),绘制选项保存在option中,绘制所用QPainter为painter,最后,这个元素所在控件为widget。
那么,我们要控制的下拉列表是什么元素呢,答案是CE_MenuItem。这里还要提到另一个方法styleHint,这个方法也是用来控制样式的:

int QProxyStyle::styleHint(StyleHint hint, const QStyleOption *option = Q_NULLPTR, const QWidget *widget = Q_NULLPTR, QStyleHintReturn *returnData = Q_NULLPTR) const
  • 1

在qss中使用“combobox-popup: 1”时,和调用styleHint方法hint参数为SH_ComboBox_Popup时返回true效果是一样的(因此你可以不使用qss将样式B修改为样式A,而是重新实现styleHint方法),SH_ComboBox_Popup在文档中的描述为:

Allows popups as a combobox drop-down menu.
  • 1

也就是将下拉列表变成一个menu。所以此时下拉列表的绘制和一个菜单的绘制是几乎相同的。
不多说了,代码如下,注释解释得比较清楚了:

void MyStyle::drawControl(ControlElement element, const QStyleOption *opt, QPainter *p,
                               const QWidget *widget) const
{
    qDebug() << element;
    switch (element)
    {
    case CE_MenuItem:
        // 进行常规的检查,确定element与opt的类别是相符的
        if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt))
        {
            // 判断控件是否为QComboBox,如果是,则使用我们指定的实现,如果不是(可能只是绘制了一个普通的菜单),则使用默认的实现
            if (qobject_cast<const QComboBox*>(widget) ||
                (opt->styleObject && opt->styleObject->property("_q_isComboBoxPopupItem").toBool()))
            {
                // 我的实现做了简化,只处理了每一项的文本和背景,对于border、margin和padding等,有需要的可以自己去实现相应的功能

                // 是否为被选择状态,如果被选择,则需要使用不同的背景色和文本色
                bool act = menuitem->state & State_Selected;

                // 绘制背景
                QBrush fill = menuitem->palette.brush(act ? QPalette::Highlight : QPalette::Button);
                p->fillRect(menuitem->rect.adjusted(0, 0, -1, 0), fill);

                // 如果文本非空,则进行绘制
                if (!menuitem->text.isEmpty()) {
                    p->save();
                    // 设置文本色
                    p->setPen(act ? menuitem->palette.highlightedText().color() : menuitem->palette.buttonText().color());
                    int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine | Qt::AlignLeft;
                    QFont font = menuitem->font;
                    p->setFont(font);
                    // 绘制在参数指定的矩形中
                    p->drawText(menuitem->rect, text_flags, menuitem->text);
                    p->restore();
                }
            }
            else
            {
                QProxyStyle::drawControl(element,opt,p,widget);
            }
        }
        break;
    default:
        QProxyStyle::drawControl(element,opt,p,widget);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

最终得到的效果如下:
样式E
左侧的空白和对勾图标都不见了,和样式A已经非常像了,如果还有什么不满意的,自己在drawControl方法中实现吧。
本文采用 CC-BY 协议进行授权 这里写图片描述

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号