QT有关QCobobox控件的样式设置(圆角、下拉框,向上展开、可编辑、内部布局等)

前言

QT设计界面时,难免会遇到修改QCombobox样式的问题。相比于其他的QLabel、QPushButton等控件,QCobobox的样式设置明显困难并复杂很多。以下介绍一下目前为止,本人参考网上代码,制作的一款QCobobox下拉框的样式风格。

效果图:
在这里插入图片描述
在这里插入图片描述

正文

一、基础样式表

/*QCombobox主体*/
QComboBox {
    border: 2px solid #f3f3f3;/*设置线宽*/
	background-color: rgb(237, 242, 255);/*背景颜色*/
    border-radius: 15px;/*圆角*/
    padding: 1px 2px 1px 2px;  /*针对于组合框中的文本内容*/
	text-align:bottom;
    min-width: 9em;   /*# 组合框的最小宽度*/
    /*min-height: 5em;*/

	border-style:solid;/*边框为实线型*/
	border-width:2px;/*边框宽度*/
	border-color:rgb(77, 123, 255);/*边框颜色*/

	padding-left: 10px;/*左侧边距*/
}
/*QCombobox右侧按钮*/
QComboBox::drop-down {
    subcontrol-origin: padding;
    subcontrol-position: top right;/*放于右方顶部*/
    width: 50px;/*设置按钮范围宽度*/
 	/*border-radius: 15px;
    border-left-width: 1px;
    border-left-color: darkgray;
    border-left-style: solid;*/

    border-top-right-radius: 3px;/*设置边框圆角*/
    border-bottom-right-radius: 3px;
/*padding-right: 50px;*/
}
/*QCombobox右侧按钮的箭头图标*/
QComboBox::down-arrow {
	border-image: url(:/image/down_list.png);/*自定义图片填充*/
	width: 10px;/*设置该图标的宽高*/
	height: 10px;
}


/* 下拉后,整个下拉窗体样式 */
QComboBox QAbstractItemView {
    border: 2px solid #f3f3f3;/*边框宽度、线形、颜色*/
	background-color: rgba(237, 242, 255, 1);/*背景颜色*/
    border-radius: 15px;/*圆角*/
    padding: 1px 2px 1px 2px;  /*针对于组合框中的文本内容*/
    min-width: 9em;   /*# 组合框的最小宽度*/
}

/* 下拉后,整个下拉窗体每项的样式 */
QComboBox QAbstractItemView::item {
	border-radius: 15px;/*圆角*/
    height: 30px;   /* 项的高度(设置pComboBox->setView(new QListView());后,该项才起作用) */
	background-color: rgb(237, 242, 255);

}

/*以下部分不知为何不生效,有待调试*/
/* 下拉后,整个下拉窗体越过每项的样式 */
QComboBox QAbstractItemView::item:hover {
    color: #FFFFF0;
       /* 整个下拉窗体越过每项的背景色 */
	background-color: rgb(98, 0, 255);
}

/* 下拉后,整个下拉窗体被选择的每项的样式 */
QComboBox QAbstractItemView::item:selected {
    color: #FFFFF0;
	background-color: rgb(0, 85, 200);
}

补充:
1.用border-radius: 15px;设置圆角的时候,该控件的高度至少要保证30px,才能显示出圆角,否则为矩形。
2.要在对应的父窗口类初始化代码中,添加setView(new QListView());,下拉框的展开框样式才会生效。

	//combobox下拉框样式表生效
    ui->comboBox->setView(new QListView());

问题:
1.下拉框的圆角和透明颜色样式无法实现

/* 下拉后,整个下拉窗体样式 */
QComboBox QAbstractItemView {
    border: 2px solid #f3f3f3;/*边框宽度、线形、颜色*/
	background-color: rgba(237, 242, 255, 1);/*背景颜色*/
    border-radius: 15px;/*圆角*/
    padding: 1px 2px 1px 2px;  /*针对于组合框中的文本内容*/
    min-width: 9em;   /*# 组合框的最小宽度*/
}

这个问题,初步猜想是因为展开框属于QWidget,可能需要重新自定义一下这个展开框,对它设置一下可透明属性。(有待验证)

2.可选项的悬浮和选中状态样式未生效

/*以下部分不知为何不生效,有待调试*/
/* 下拉后,整个下拉窗体越过每项的样式 */
QComboBox QAbstractItemView::item:hover {
    color: #FFFFF0;
       /* 整个下拉窗体越过每项的背景色 */
	background-color: rgb(98, 0, 255);
}

/* 下拉后,整个下拉窗体被选择的每项的样式 */
QComboBox QAbstractItemView::item:selected {
    color: #FFFFF0;
	background-color: rgb(0, 85, 200);
}

3.QCombobox的文本无法居中
之前好像稍微查过,实现起来比较麻烦。成功了的朋友可以在评论区交流一下~~

二、ui designer直接添加可选项

如图:
在这里插入图片描述
这里可以设置icon大小
在这里插入图片描述

三、代码添加可选项

更为常见的,其实是程序在运行过程中,动态对QCombobox填充可选项。比如登录时填充人名数据、选择摄像头分辨率时的分辨率列表等等不固定的元素。
以下是具体操作的代码,有点多但很简单:

	//填充下拉选项
    ui->comboBox->clear();//清空combobox
    QStandardItemModel *pItemModel = qobject_cast<QStandardItemModel*>(ui->comboBox->model());

    //字体设置
    int combobox_item_fontsize = 9;
    QFont font;
    //font.setPixelSize(combobox_item_fontsize*scale);
    font.setPointSize(combobox_item_fontsize);
    font.setFamily("黑体");

    //填充默认项(在没有任何数据时,可以先做一个默认的提示项给用户,然后让用户自己输入)
    QString tip_string(u8"请选择用户名");
    ui->comboBox->addItem(tip_string);
    pItemModel->item(0)->setIcon(QIcon(":/image/account.png"));    //修改某项图标
    pItemModel->item(0)->setForeground(QColor(255, 0, 0));            //修改某项文本颜色
    pItemModel->item(0)->setBackground(QColor(220,220,220));    //修改某项背景颜色
    pItemModel->item(0)->setFont(font);
    pItemModel->item(0)->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);    //修改某项文本对齐方式

    //填充正式项
    if(ui->comboBox->currentText() == tip_string)
        ui->comboBox->clear();

    int i= 0;
    QStringList m_list;//随便来点填充数据
    m_list<<"AAA"<<"BBB"<<"CCC"<<"DDD";
    foreach (QString name, m_list)
    {
        qDebug()<<"combobox additem:"<<name;
        ui->comboBox->addItem(name);

        pItemModel->item(i)->setIcon(QIcon(":/image/account.png"));    //修改某项图标
        //pItemModel->item(i)->setText("修改的文本  " + QString::number(i + 1));                          //修改某项文本
        //pItemModel->item(i)->setForeground(QColor(255, 0, 0));            //修改某项文本颜色
        //pItemModel->item(i)->setBackground(QColor(220,220,220));    //修改某项背景颜色(若样式表中已经设置了表项的背景颜色,则不会生效)
        pItemModel->item(i)->setFont(font);
        pItemModel->item(i)->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);    //修改某项文本对齐方式
        i++;
    }

    //以上设置完,会默认选择第一项。可以手动选择-1项,即为未选择状态
    //ui->comboBox->setCurrentIndex(-1);

四、下拉框向上展开

有些时候,我们期望QCombobox的下拉框向上展开,例如控件已经来到屏幕下方边缘,若按照原本的向下展开,则被任务栏遮挡一部分。(虽然超出屏幕边缘这种情况,它好像自动会向上展开,不过总有向上展开的需求hh)
方法就是重新自定义一个类,继承QCombobox类,然后重载showPopup();函数

void showPopup() override;

void myCombox::showPopup()
{
    QComboBox::showPopup();
    QWidget *popup = this->findChild<QFrame*>();
	
	//针对当前ui布局,计算QCombobox全局坐标
    int combobox_y = static_cast<MainWindow *>(this->parent()->parent()->parent()->parent())->y() +
            static_cast<QWidget *>(this->parent()->parent()->parent())->y() +
            static_cast<QWidget *>(this->parent()->parent())->y()+
            static_cast<QWidget *>(this->parent())->y()+
            this->y();
    if(popup->y() > combobox_y)
    {
        popup->move(popup->x(),popup->y()-this->height()-popup->height());//x轴不变,y轴向上移动 list的高+combox的高

    }else{
        //popup->move(popup->x(),popup->y()-this->height()-popup->height());//x轴不变,y轴向上移动 list的高+combox的高
    }
}

展开的行为就是QComboBox::showPopup();,展开的窗口则是QWidget (所以其实还可以再优化得更好一点)
然后就是对这个窗口的移动。它肯定有一个默认的展开框的默认位置。
逻辑简单来说就是,先计算一下QCombobox的全局y坐标。然后再对比当前实际展开框的y值,判断其是向上展开还是向下展开的。
如果是向下展开,则手动move一下他,y值减少QCombobox的高度和展开框的高度,就能实现向上展开了。

另外,我计算QCombobox全局坐标的时候笨得要死hh,其实还有其他的算法,你们自己尝试吧。

五、详细样式表(编辑模式的状态)

(参考Qt.QComboBox样式表

/* 未下拉时,QComboBox的样式 */
QComboBox {
    border: 1px solid gray;   /* 边框 */
    border-radius: 3px;   /* 圆角 */
    padding: 1px 18px 1px 3px;   /* 字体填衬 */
    color: #000;
    font: normal normal 15px "Microsoft YaHei";
    background: transparent;
}

/* 下拉后,整个下拉窗体样式 */
QComboBox QAbstractItemView {
    outline: 0px solid gray;   /* 选定项的虚框 */
    border: 1px solid yellow;   /* 整个下拉窗体的边框 */
    color: green;
    background-color: red;   /* 整个下拉窗体的背景色 */
    selection-background-color: lightgreen;   /* 整个下拉窗体被选中项的背景色 */
}

/* 下拉后,整个下拉窗体每项的样式 */
QComboBox QAbstractItemView::item {
    height: 50px;   /* 项的高度(设置pComboBox->setView(new QListView());后,该项才起作用) */
}

/* 下拉后,整个下拉窗体越过每项的样式 */
QComboBox QAbstractItemView::item:hover {
    color: #FFFFFF;
    background-color: lightgreen;   /* 整个下拉窗体越过每项的背景色 */
}

/* 下拉后,整个下拉窗体被选择的每项的样式 */
QComboBox QAbstractItemView::item:selected {
    color: #FFFFFF;
    background-color: lightgreen;
}

/* QComboBox中的垂直滚动条 */
QComboBox QAbstractScrollArea QScrollBar:vertical {
    width: 10px;
    background-color: #d0d2d4;   /* 空白区域的背景色  灰色green */
}

QComboBox QAbstractScrollArea QScrollBar::handle:vertical {
    border-radius: 5px;   /* 圆角 */
    background: rgb(160,160,160);   /* 小方块的背景色深灰lightblue */
}

QComboBox QAbstractScrollArea QScrollBar::handle:vertical:hover {
    background: rgb(90, 91, 93);   /* 越过小方块的背景色yellow */
}

/* 设置为可编辑(setEditable(true))editable时,编辑区域的样式 */
QComboBox:editable {
    background: green;
}

/* 设置为非编辑(setEditable(false))!editable时,整个QComboBox的样式 */
QComboBox:!editable {
     background: blue;
}

/* 设置为可编辑editable时,点击整个QComboBox的样式 */
QComboBox:editable:on {
    background: green;
}

/* 设置为非编辑!editable时,点击整个QComboBox的样式 */
QComboBox:!editable:on {
     background: blue;
}

/* 设置为可编辑editable时,下拉框的样式 */
QComboBox::drop-down:editable {
    background: lightblue;
}

/* 设置为可编辑editable时,点击下拉框的样式 */
QComboBox::drop-down:editable:on {
    background: lightgreen;
}

/* 设置为非编辑!editable时,下拉框的样式 */
QComboBox::drop-down:!editable {
    background: lightblue;
}

/* 设置为非编辑!editable时,点击下拉框的样式 */
QComboBox::drop-down:!editable:on {
    background: lightgreen;
}

/* 点击QComboBox */
QComboBox:on {
}

/* 下拉框样式 */
QComboBox::drop-down {
    subcontrol-origin: padding;   /* 子控件在父元素中的原点矩形。如果未指定此属性,则默认为padding。 */
    subcontrol-position: top right;   /* 下拉框的位置(右上) */
    width: 15px;   /* 下拉框的宽度 */

    border-left-width: 1px;   /* 下拉框的左边界线宽度 */
    border-left-color: darkgray;   /* 下拉框的左边界线颜色 */
    border-left-style: solid;   /* 下拉框的左边界线为实线 */
    border-top-right-radius: 3px;   /* 下拉框的右上边界线的圆角半径(应和整个QComboBox右上边界线的圆角半径一致) */
    border-bottom-right-radius: 3px;   /* 同上 */
}

/* 下拉箭头样式 */
QComboBox::down-arrow {
    width: 15px;   /* 下拉箭头的宽度(建议与下拉框drop-down的宽度一致) */
    background: transparent;   /* 下拉箭头的的背景色 */
    padding: 0px 0px 0px 0px;   /* 上内边距、右内边距、下内边距、左内边距 */
    image: url(:/images/combobox_arrow_down.png);
}

/* 点击下拉箭头 */
QComboBox::down-arrow:on {
    image: url(:/images/combobox_arrow_up.png);   /* 显示下拉箭头 */
}

这个版本他考虑到了编辑模式的状态,而且分得很详细,可以学习一下。

1.遇到的坑
我们知道,如果想要改变QCombobox的字体,只需要setFont()就可以了,也就是

ui->comboBox->setFont(font);

但是当我们选中了可编辑的状态时,往往显示的文本字体却没有发生改变

ui.comboBox->setEditable(true);
//此后字体设置无效

这是因为常态的文本显示和可编辑状态下的显示时不一样的,按照我的理解的话,就是一个是内嵌了QLabel显示文本,另一个是内嵌了QLineEdit,用来进行文字的输入。所以这时,我们的修改对象变成了QCombobox的子对象QLineEdit:


ui->comboBox->lineEdit()->setFont(font);

这样的话,才真正响应设置成功

六、QCombobox内部的布局

按照第五步,我才终于意识到原来QCombobox只是一个集合的容器部件,它的里面其实封装了很多其他的东西,所以它才有什么lineedit和qicon什么的嘛。
那么就衍生出了另一种样式设置的方式,那就是直接设置内部的布局,如下:

	QLabel *man = new QLabel(this);
    man->setFixedSize(20*scale, 20*scale);
    man->setCursor(QCursor(Qt::ArrowCursor));
    man->setPixmap(QPixmap(":/login/icon_account.png"));
    man->setScaledContents(true);

    QSpacerItem *spaceItem_name = new QSpacerItem(100, 10, QSizePolicy::Expanding);
    QHBoxLayout *editLayout_name = new QHBoxLayout();
    editLayout_name->setContentsMargins(14*scale, 0, 0, 0);
    editLayout_name->addWidget(man);
    editLayout_name->addSpacerItem(spaceItem_name);
    ui.comboBox->setLayout(editLayout_name);

如果你有手动代码布局的经验的话,应该能轻松看懂这种设置的方式。我这段代码的话,就是先用QLabel创建一个图标,然后加一条弹簧,在把layout设置进去。用这种做法的话,效果和直接样式表的设置一样,甚至更好更灵活。

比如如果拖拉窗口改变了QCombobox的尺寸,那顺带着也可以改变图标的尺寸了,你不想改变的话就Fix设置定死,但这种方式在跨屏的、不同分辨率底下显示器,需要完美适配的情况下,能够省下不少工作量。

你也可以做成左边图标,中间弹簧,右边下拉箭头的图标,这样只需要在样式表里面设置文本左右的间距,就能完美实现你想要的任何布局了。

  • 42
    点赞
  • 243
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要将QTTableWidget中的某一列设置下拉框设置默认值,可以通过自定义QComboBox委托实现。下面是一个示例代码: ```python from PyQt5.QtWidgets import QComboBox, QTableWidgetItem, QTableWidget, QApplication, QWidget, QHBoxLayout, QTableWidgetItem, QStyledItemDelegate class ComboBoxDelegate(QStyledItemDelegate): def __init__(self, choices=[], parent=None): super().__init__(parent) self.items = choices def createEditor(self, parent, option, index): editor = QComboBox(parent) editor.addItems(self.items) return editor def setEditorData(self, editor, index): value = index.data() editor.setCurrentIndex(editor.findText(value)) def setModelData(self, editor, model, index): value = editor.currentText() model.setData(index, value, 0) class MyTableWidget(QTableWidget): def __init__(self, parent=None): super().__init__(parent) self.setColumnCount(2) self.setHorizontalHeaderLabels(['Name', 'Gender']) self.setItemDelegateForColumn(1, ComboBoxDelegate(["Male", "Female"], self)) self.setRowCount(1) self.setItem(0, 0, QTableWidgetItem("Tom")) self.setItem(0, 1, QTableWidgetItem("Male")) if __name__ == '__main__': app = QApplication([]) widget = MyTableWidget() widget.show() app.exec_() ``` 在上述代码中,我们首先定义了一个自定义的QStyledItemDelegate,它继承自QStyledItemDelegate,并重写了createEditor、setEditorData和setModelData方法,分别用于创建下拉框设置下拉框的默认值和将下拉框的值更新到数据模型中。 然后,在MyTableWidget中,我们将第二列设置为ComboBoxDelegate,并将其选项设置为["Male", "Female"],这样就将第二列设置为了下拉框,并且默认值为"Male"。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值