给下拉框增加按钮是常见的功能,如 QQ 账号输入框的下拉:
网上有不少 Qt 实现的例子,实现方式也很多,在参照了别人的思路后我也实现了选项带按钮的下拉框。中间遇到不少坑,最后效果也不完美。
我选的是 QListWidget + QListWidgetItem 的方式,因为感觉相对简单点,而且和样式表更好搭配。这种方式主要是把 QListWidget作为 QComboBox 的 View ,List 的 model 也设置为 QComboBox 的 model,这样展现出来的选项就是一个 QListWidgetItem,我们只需要把按钮设置到 QListWidgetItem 的 widget 中就行了。
这里面还有个问题是, 要让 QComboBox 读取到对应项的文本,还要给 QListWidgetItem 加一句这个:
QListWidgetItem* item_widget = new QListWidgetItem();
//设置显示的data,这样combox才有文字
item_widget->setData(Qt::DisplayRole,"text");
然后来看一下比较简单的实现:
QListWidget *item_list=new QListWidget(this);
ui->comboBoxA->setModel(item_list->model());
ui->comboBoxA->setView(item_list);
//添加选项
for(int i=0;i<5;i++)
{
//组合一个带按钮的widget
QWidget *item_widget=new QWidget();
QHBoxLayout *layout=new QHBoxLayout(item_widget);
layout->addStretch(); //弹簧
QPushButton *btn=new QPushButton(item_widget);
layout->addWidget(btn);
layout->setMargin(0);
layout->setSpacing(0);
QListWidgetItem* item_wrap = new QListWidgetItem(item_list);
//测试长文字
QString text=(i==0)?"text long long long":"text";
//设置显示的data,这样combox才有文字
item_wrap->setData(Qt::DisplayRole,text);
item_list->setItemWidget(item_wrap,item_widget);
connect(btn,&QPushButton::clicked,this,[=](){
ui->comboBoxA->hidePopup(); //没有刷新弹框大小
item_list->takeItem(item_list->row(item_wrap));
delete item_wrap;
});
}
很快就发现了问题,文字足够长时,选项整体宽度被拉长了,导致按钮位置超出了显示范围(下图蓝色框部分):
(按钮位置我是配合样式表的 margin 调整的,可见源代码)
索性我就继承了 QListWidget,重写了他的 visualRect 接口,在有滚动条时,rect 就去掉滚动条的宽度:
QRect ComboView::visualRect(const QModelIndex &index) const
{
QRect rect=QListWidget::visualRect(index);
int width=this->width();
if(verticalScrollBar()->isVisible()){
width-=verticalScrollBar()->width();
}
rect.setWidth(width);
return rect;
}
这下就能把选项挤过来了:
这里还有个滚动条占位得问题没解决,我的想法是显示或增删选项时去判断是否有滚动条,然后调整按钮的 margin。
github 链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qt/MyComboBox
主要实现(比较忙, demo 没怎么写注释):
#ifndef MYCOMBOBOX_H
#define MYCOMBOBOX_H
#include
#include
#include
#include
#include
#include
class ComboView : public QListWidget
{
Q_OBJECT
public:
explicit ComboView(QWidget * parent=nullptr);
QRect visualRect(const QModelIndex &index) const override;
};
class ComboItem : public QWidget
{
Q_OBJECT
public:
explicit ComboItem(const QString &text,QWidget *parent = nullptr);
~ComboItem();
QString text() const;
signals:
void itemClicked(const QString &text);
private:
QString textValue;
QPushButton *btn;
};
class MyComboBox : public QComboBox
{
Q_OBJECT
public:
explicit MyComboBox(QWidget *parent = nullptr);
void setRemovableItems(const QStringList &items);
signals:
void itemRemoved(const QString &text);
private:
QListWidget *itemList;
};
#endif // MYCOMBOBOX_H
#include "MyComboBox.h"
#include
#include
#include
#include
#include
#include
ComboView::ComboView(QWidget *parent)
: QListWidget(parent)
{
}
QRect ComboView::visualRect(const QModelIndex &index) const
{
QRect rect=QListWidget::visualRect(index);
int width=this->width();
if(verticalScrollBar()->isVisible()){
width-=verticalScrollBar()->width();
}
rect.setWidth(width);
return rect;
}
ComboItem::ComboItem(const QString &text, QWidget *parent)
: QWidget(parent),
textValue(text),
btn(new QPushButton(this))
{
QHBoxLayout *layout=new QHBoxLayout(this);
layout->addStretch();
layout->addWidget(btn);
layout->setMargin(0);
layout->setSpacing(0);
connect(btn,&QPushButton::clicked,[this]{
emit itemClicked(textValue);
});
}
ComboItem::~ComboItem()
{
qDebug()<<"~delete"<setTextElideMode(Qt::ElideNone);
setModel(itemList->model());
setView(itemList);
}
void MyComboBox::setRemovableItems(const QStringList &items)
{
//combox的additem insertitem不是虚函数
//实现里时调用的model->insertRow,但是懒得再去重写listmodel-view,就新增一个接口
itemList->clear();
if(items.isEmpty())
return;
for(int i=0;isetData(Qt::DisplayRole,items.at(i));
//widget_item->setData(Qt::TextAlignmentRole,int(Qt::AlignRight|Qt::AlignVCenter));
itemList->setItemWidget(widget_item,item);
connect(item,&ComboItem::itemClicked,this,[this,item,widget_item](){
//take移除item后没有刷新弹框大小,干脆隐藏掉先
hidePopup();
itemList->takeItem(itemList->row(widget_item));
delete widget_item;
emit itemRemoved(item->text());
});
}
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "MyComboBox.h"
#include
#include
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//【1】 ui上的QComboBox
QListWidget *item_list=new QListWidget(this);
ui->comboBoxA->setModel(item_list->model());
ui->comboBoxA->setView(item_list);
//添加选项
for(int i=0;i<5;i++)
{
//组合一个带按钮的widget
QWidget *item_widget=new QWidget();
QHBoxLayout *layout=new QHBoxLayout(item_widget);
layout->addStretch(); //弹簧
QPushButton *btn=new QPushButton(item_widget);
layout->addWidget(btn);
layout->setMargin(0);
layout->setSpacing(0);
QListWidgetItem* item_wrap = new QListWidgetItem(item_list);
//测试长文字
QString text=(i==0)?"text long long long":"text";
//设置显示的data,这样combox才有文字
item_wrap->setData(Qt::DisplayRole,text);
item_list->setItemWidget(item_wrap,item_widget);
connect(btn,&QPushButton::clicked,this,[=](){
ui->comboBoxA->hidePopup(); //没有刷新弹框大小
item_list->takeItem(item_list->row(item_wrap));
delete item_wrap;
});
}
//【2】ui上的combobox提升为自定义子类
QStringList str_list{
"1234567891011+++++++++++++",
"2234567891011",
"323",
"423",
"523",
"623",
"723",
"823",
"123",
"123",
"123"
};
ui->comboBoxB->setRemovableItems(str_list);
//ui->comboBoxB->setMaxVisibleItems(20);
connect(ui->comboBoxB,&MyComboBox::itemRemoved,this,[=](const QString &text){
qDebug()<<"item remove"<comboBox_2->clear();
});
}
/*下拉框*/
QComboBox{
min-width:1px;
min-height:26px;
padding-left: 5px;
padding-right: 2px;
color: white;
border:1px solid rgb(128, 128, 128);
background-color: rgb(100 ,100 ,100);
}
QComboBox:on{
/*弹出为on*/
}
QComboBox:hover{
border:1px solid rgb(255, 170, 0);
}
QComboBox:disabled{
color: rgb(230, 230, 230);
background-color:rgb(150, 150, 150);
}
QComboBox:editable{
background-color:rgb(100, 100, 100);
}
QComboBox:editable:disabled{
background-color:rgb(150, 150, 150);
}
/*下拉按钮-配合贴图*/
QComboBox::drop-down{
min-width:24px;
}
/*下拉框弹出项*/
QComboBox QAbstractItemView{
font: 15px "宋体";
background-color:rgb(110, 110, 110);
}
QComboBox QAbstractItemView::item{
height:24px;
color:white;
}
QComboBox QAbstractItemView::item:hover{
background-color: rgb(255, 170, 0);
}
QComboBox QAbstractItemView::item:selected{
background-color: rgb(255, 170, 0);
}
/*按钮样式*/
QComboBox QAbstractItemView QPushButton{
max-width:20px;
min-width:20px;
max-height:20px;
min-height:20px;
border:0;
margin-right:20px;
background-color:white;
}
QComboBox QAbstractItemView QPushButton:hover{
background-color:cyan;
}
博客:https://blog.csdn.net/wukai_std/article/details/60144318
博客:http://blog.sina.com.cn/s/blog_a6fb6cc90102vces.html