如何使 QComboBox 的文本加粗,而不是列表项?

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

我们的 UI 中有一个长期约定,即项目在已更改但尚未提交更改时以粗体显示。奇怪的是,直到现在我们还没有使用任何组合框,但我现在有一个用途并且需要实现这种行为。所以我需要以编程方式将关闭的组合框显示的文本加粗(然后取消加粗)。但是,我不想在弹出窗口中将整个项目列表加粗。如果这样更容易的话,我可以接受将列表中的选定项目加粗。

我已经看到很多答案几乎都是这样做的,但通常是尝试修改列表项而不是按钮。我已经尝试了其中大多数的变体;不幸的是,我没有保留我尝试过的记录。对于它的价值,我的代码目前看起来像:

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

这会将按钮变为粗体,同时也会将列表项变为粗体。当我将正常权重仅应用于 QAbstractItemView 而没有 ::item 时,以及当我尝试基于 :open:closed 的不同技术时,会看到相同的行为 QComboBox.

我会说我是 Qt 的新手。我在 Fedora 26 上使用 Qt5,但将部署到 CentOS 7。

似乎在 QComboBox 中设置字体样式覆盖了视图(恕我直言,它不应该)。

但是,当我尝试以这种方式显式设置组合框的视图时:

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

OP 发布的样式表突然起作用了。

顺便说一句,新视图与原始视图不同(例如,有白色背景等),我猜 OP 对此不满意。当然,人们可以继续设计它的样式,但人们更愿意使用一种具有一致风格的即用型视图。

检查默认 QComboBox 视图:

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

产生这个:

QComboBoxListView(0x2091880)

所以,有一个特定的 QComboBoxListView class,在文档中找不到,在 qcombobox_p.h 中定义,不是一个可以包含的文件,真的,但至少我们可以在 viewOptions 重写方法中理解问题的来源:

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

那个combo是指向QComboBox的私有指针,在构造中初始化:

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

它将始终用自己的字体覆盖视图选项字体。

让我们复制一份 QComboBoxListView class,编辑并重命名:

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

最后用它来设置视图字体的样式:

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