如何使QComboBox的文本加粗,但不包括列表项?

3
我们的用户界面有一个长期惯例,当项目已更改但尚未提交更改时以粗体显示。奇怪的是,到目前为止我们还没有使用任何组合框,但我现在需要使用一个并且需要实现此行为。因此,我需要以编程方式将封闭组合框显示的文本加粗(然后取消加粗)。但是,我不想加粗弹出窗口中所有项目的整个列表。如果这样更容易,我可以接受在列表中加粗所选项目。我看到很多答案都做得差不多,但通常是尝试修改列表项而不是按钮。我已经尝试了大部分变化,但不幸的是我没有记录下我尝试过什么。就它的价值而言,我的代码当前看起来像:
myCombo->setStyleSheet(
    "QComboBox {font-weight: bold;} "
    "QComboBox QAbstractItemView::item {font-weight: normal;}"
);

这会使按钮加粗,但列表项也会加粗。如果我只对 QAbstractItemView 应用普通字重,而不是应用到 ::item 上,或者尝试基于 :open:closedQComboBox 上使用不同的技术,都会出现相同的行为。
我要说我对Qt还比较新。我在Fedora 26上使用Qt5,但将部署到CentOS 7。

1
当你谈论QComboBoxes时,"button"是什么意思? - SteakOverflow
抱歉,我不确定正确的术语。我的意思是当QComboBox关闭时,显示当前选定项而没有其他项的文本。 - Pete
1个回答

1
似乎在QComboBox中设置字体样式会覆盖视图的字体样式(我认为不应该这样)。
但是,当我尝试显式地将视图设置给组合框时,使用以下方式:
  view = new QListView();
  myCombo->setView(view);

原帖中发布的样式表突然起作用了。

顺便说一下,新视图与原始视图不同(例如有白色背景等),我猜原作者对此不太满意。当然,可以继续进行样式设置,但更希望有一个准备好的视图,具有一致的样式。

检查默认的QComboBox视图:

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

产生以下结果:
QComboBoxListView(0x2091880)
因此,有一个特定的 QComboBoxListView 类,在文档中找不到,在 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类:

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

谢谢 - 我认为第一种方法对我来说是可接受的,在这种情况下基本的ListView看起来合理。第二种方法似乎有点繁琐,虽然无疑是有效的。 - Pete
好的,这真的很粗糙。我进一步调查后发现了更好的解决方案,并相应地编辑了答案。 - p-a-o-l-o

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接