简体   繁体   中英

How to make the text of a QComboBox bold, but not the list items?

We have a longstanding convention in our UI that items are shown in bold when they have been changed but the change is not yet committed. Strangely, until now we haven't used any combo boxes, but I have a use for one now and need to implement this behaviour. So I need to programmatically bold (and later un-bold) the text displayed by a closed combo box. However, I don't want to bold the entire list of items in the pop-up. I could accept bolding the selected item in the list if that's easier.

I've seen lots of answers doing almost this, but usually trying to modify the list items rather than the button. I've tried variations on most of them; unfortunately I didn't keep records of what I tried. For what it's worth, my code currently looks like:

myCombo->setStyleSheet(
    "QComboBox {font-weight: bold;} "
    "QComboBox QAbstractItemView::item {font-weight: normal;}"
);

This turns the button bold, but also the list items. The same behaviour is seen when I apply the normal weight just to the QAbstractItemView without the ::item , and when I tried a different technique based on :open and :closed on the QComboBox .

I will say I'm fairly new to Qt. I am using Qt5 on Fedora 26, but will be deploying to CentOS 7.

It seems that setting the font-style in QComboBox overrides the view's (and it shouldn't, IMHO).

But, when I tried to explicitly set a view to the combo box, this way:

  view = new QListView();
  myCombo->setView(view);

the stylesheet posted by the OP suddenly worked.

By the way, the new view is different from the original (eg has a white background, etc) and I guess the OP isn't happy with that. One could go on styling it, of course, but one would rather prefer a ready to use view, with a consistent style.

Inspecting the default QComboBox view:

QComboBox * combo = new QComboBox();
qDebug() << combo->view();

yelds this:

 QComboBoxListView(0x2091880) 

So, there is a specific QComboBoxListView class, which is nowhere to be found in documentation and is defined in qcombobox_p.h , not a file one could include, really, but at least we can understand where the issue come from, in the viewOptions overridden method:

    QStyleOptionViewItem option = QListView::viewOptions();
    option.showDecorationSelected = true;
    if (combo)
        option.font = combo->font(); // <--- here
    return option;

That combo is a private pointer to QComboBox , initialized in construction:

    QComboBoxListView(QComboBox *cmb = 0) : combo(cmb) {}

which will always override the view options font with its own.

Let's have a copy of the QComboBoxListView class, edited and renamed:

comboitemview.h

#ifndef COMBOITEMVIEW_H
#define COMBOITEMVIEW_H

#include <QListView>
#include <QComboBox>

class ComboItemView : public QListView
{
    Q_OBJECT

    QComboBox * _box;
public:
    ComboItemView(QComboBox *box);
protected:
    void paintEvent(QPaintEvent *event);
    void resizeEvent(QResizeEvent *event);
    QStyleOptionViewItem viewOptions() const;
};

#endif // COMBOITEMVIEW_H

comboitemview.cpp

#include "comboitemview.h"

#include <QPaintEvent>
#include <QPainter>

ComboItemView::ComboItemView(QComboBox * box = 0) : _box(box){}

void ComboItemView::paintEvent(QPaintEvent *event)
{
    if (_box)
    {
        QStyleOptionComboBox opt;
        opt.initFrom(_box);
        opt.editable = _box->isEditable();
        if (_box->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, _box))
        {
            QStyleOptionMenuItem menuOpt;
            menuOpt.initFrom(this);
            menuOpt.palette = palette();
            menuOpt.state = QStyle::State_None;
            menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
            menuOpt.menuRect = event->rect();
            menuOpt.maxIconWidth = 0;
            menuOpt.tabWidth = 0;
            QPainter p(viewport());
            _box->style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOpt, &p, this);
        }
    }
    QListView::paintEvent(event);
}

void ComboItemView::resizeEvent(QResizeEvent *event)
{
    resizeContents(viewport()->width(), contentsSize().height());
    QListView::resizeEvent(event);
}

QStyleOptionViewItem ComboItemView::viewOptions() const
{
    QStyleOptionViewItem option = QListView::viewOptions();
    option.showDecorationSelected = true;
    return option;
}

And finally use it to style the view font:

    myCombo->setView(new ComboItemView(myCombo));
    myCombo->setStyleSheet(
                "QComboBox {font-weight: bold;} "
                "QComboBox QAbstractItemView {font-weight: normal;}"
    );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM