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设置定死,但这种方式在跨屏的、不同分辨率底下显示器,需要完美适配的情况下,能够省下不少工作量。

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

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值