当前位置:网站首页>Qt 下拉复选框(MultiSelectComboBox)(一) 实现下拉框多选,搜索下拉框内容
Qt 下拉复选框(MultiSelectComboBox)(一) 实现下拉框多选,搜索下拉框内容
2022-08-03 08:15:00 【Bejpse】
文章目录
前言
刚开始学习qt时,在遇到下拉复选框问题的时候总是使用表格来实现这个功能,因为表格单元格可以添加代理,而QComboBox类对象在设置代理后总是不生效。使用表格来实现,如果需求本来就是在表格中还好,但有时候只是需要一个下拉复选框,这个时候就需要隐藏边框,设置单元双击输入框禁用等等,会非常麻烦,而且最后的效果也是不敬人意,所以在仔细研究了QComboBox类对象之后,参考github大佬的示例实现了一个比较好用的下拉复选框。
参考博客地址:https://blog.csdn.net/u013135921/article/details/79437392
以下是本篇文章正文内容,主要实现功能,下面案例可供参考
一、QCombobox的组成
QComboBox类对象由三部分组成:QLineEdit、QToolButton、QListWidget。
- QLineEdit负责选中选项的显示,由此要设置为不可编辑状态。
- QToolButton是一个弹出与隐藏下拉框的按钮。
- QListWidget是最重要的一部分,所有选项内容显示的格式,自定义功能的添加主要都集中在这部分。
二、MultiSelectComboBox实现
1. 总体实现
整个控件继承于QCombobox类。主要修改QLineEdit、QListWidget这两部分,QComboBox提供如下接口,可以将这两部分设置为新建的QLineEdit、QListWidget对象 ( line_edit_,list_widget_)。
代码如下(示例):
this->setView(list_widget_);
this->setLineEdit(line_edit_);
- line_edit_部分用来显示选择的结果和弹出下拉框,显示内容使用 “;” 进行分割
- list_widget_下拉框部分,显示搜索框与选项。QListWidget类对象可以通过设置Item,在item中添加QWidget对象来实现一些特殊功能。这里的list_widget_,搜索框为QlineEdit类对象,用户输入搜索条件后显示符合条件的选项,用来解决选项过多的问题,选项为QCheckBox类对象,有“选中”和“未选中”两种状态。
2. QLineEdit部分
这部分用来显示选择的结果和弹出下拉框,显示内容使用 “;” 进行分割。这里设置了点击QLineEdit也可以弹出下拉框,需要先将当前line_edit_对象安装(或注册)为事件过滤器,再重写eventFilter()函数。
代码如下(示例):
/*设置文本框*/
//设为只读,因为该输入框只用来显示选中的选项,称为文本框更合适些
line_edit_->setReadOnly(true);
//把当前对象安装(或注册)为事件过滤器,当前也称为过滤器对象。事件过滤器通常在构造函数中进行注册。
line_edit_->installEventFilter(this);
//设置禁用样式,因为不受样式表控制,临时这样解决
line_edit_->setStyleSheet("QLineEdit:disabled{background:rgb(233,233,233);}");
bool MultiSelectComboBox::eventFilter(QObject *watched, QEvent *event)
{
//设置点击输入框也可以弹出下拉框
if (watched == line_edit_ && event->type() == QEvent::MouseButtonRelease && this->isEnabled())
{
showPopup();
return true;
}
return false;
}
3. QListWidget部分
下拉框部分,显示搜索框与选项。
1. 搜索框部分
设置list_widget_第一项的itemWidget为QLineEdit,用来输入检索条件,绑定textChanged(const QString&)信号,当输入内容发生变化时,下面显示选项发生相应变化。
初始化代码如下(示例):
/*设置搜索框*/
QListWidgetItem* currentItem = new QListWidgetItem(list_widget_);
//设置搜索框提示信息
search_bar_->setPlaceholderText("Search.........");
//显示清除按钮
search_bar_->setClearButtonEnabled(true);
list_widget_->addItem(currentItem);
list_widget_->setItemWidget(currentItem, search_bar_);
输入文本变化槽函数代码如下(示例):
connect(search_bar_, SIGNAL(textChanged(const QString&)), this, SLOT(onSearch(const QString&)));
void MultiSelectComboBox::onSearch(const QString& _text)
{
for (int i = 1; i < list_widget_->count(); i++)
{
QCheckBox *check_box = static_cast<QCheckBox*>(list_widget_->itemWidget(list_widget_->item(i)));
//文本匹配则显示,反之隐藏
//Qt::CaseInsensitive模糊查询
if (check_box->text().contains(_text, Qt::CaseInsensitive))
list_widget_->item(i)->setHidden(false);
else
list_widget_->item(i)->setHidden(true);
}
}
2. 选项部分
单击选项选中,选中后更新line_edit_内容,绑定stateChanged信号,鼠标单击选项时时,就会将所有选项遍历一遍,然后把选中的选项组织为字符串,更新到line_edit_上。发送信号void selectionChange(const QString _data);,此信号为选中选项发送变化时发出。
选项变化槽函数代码如下(示例):
connect(checkbox, &QCheckBox::stateChanged, this, &MultiSelectComboBox::stateChange);
void MultiSelectComboBox::stateChange(int _row)
{
Q_UNUSED(_row);
QString selected_data("");
int count = list_widget_->count();
for (int i = 1; i < count; i++)
{
QWidget *widget = list_widget_->itemWidget(list_widget_->item(i));
QCheckBox *check_box = static_cast<QCheckBox*>(widget);
if (check_box->isChecked())
{
selected_data.append(check_box->text()).append(";");
}
}
selected_data.chop(1);
if (!selected_data.isEmpty())
{
line_edit_->setText(selected_data);
}
else
{
line_edit_->clear();
}
line_edit_->setToolTip(selected_data);
emit selectionChange(selected_data);
}
4. 对外接口定义
考虑到使用方便,这里定义了一些接口方便用户使用,接口含义见下方注释 (文本框代表line_edit_)。
接口定义如下(示例):
//隐藏下拉框
virtual void hidePopup();
//添加一条选项
void addItem(const QString& _text, const QVariant& _variant = QVariant());
//添加多条选项
void addItems(const QStringList& _text_list);
//返回当前选中选项
QStringList currentText();
//返回当前选项条数
int count()const;
//设置搜索框默认文字
void SetSearchBarPlaceHolderText(const QString _text);
//设置文本框默认文字
void SetPlaceHolderText(const QString& _text);
//下拉框状态恢复默认(所有选项都恢复为未选中状态)
void ResetSelection();
//清空所有内容(选项内容全部清空)
void clear();
//文本框内容清空(选项内容不清空,所有选项都恢复为未选中状态,文本框清空)
void TextClear();
//设置选中文本--单
void setCurrentText(const QString& _text);
//设置选中文本--多
void setCurrentText(const QStringList& _text_list);
//设置搜索框是否禁用
void SetSearchBarHidden(bool _flag);
5. 代码实现
头文件:
#pragma once
#include <QComboBox>
#include <QListWidget>
#include <QLineEdit>
#include <QCheckBox>
#include <QEvent>
class MultiSelectComboBox : public QComboBox
{
Q_OBJECT
public:
MultiSelectComboBox(QWidget *parent = Q_NULLPTR);
~MultiSelectComboBox();
//隐藏下拉框
virtual void hidePopup();
//添加一条选项
void addItem(const QString& _text, const QVariant& _variant = QVariant());
//添加多条选项
void addItems(const QStringList& _text_list);
//返回当前选中选项
QStringList currentText();
//返回当前选项条数
int count()const;
//设置搜索框默认文字
void SetSearchBarPlaceHolderText(const QString _text);
//设置文本框默认文字
void SetPlaceHolderText(const QString& _text);
//下拉框状态恢复默认
void ResetSelection();
//清空所有内容
void clear();
//文本框内容清空
void TextClear();
//设置选中文本--单
void setCurrentText(const QString& _text);
//设置选中文本--多
void setCurrentText(const QStringList& _text_list);
//设置搜索框是否禁用
void SetSearchBarHidden(bool _flag);
protected:
//事件过滤器
virtual bool eventFilter(QObject *watched,QEvent *event);
//滚轮事件
virtual void wheelEvent(QWheelEvent *event);
//按键事件
virtual void keyPressEvent(QKeyEvent *event);
private slots:
//槽函数:文本框文本变化
void stateChange(int _row);
//槽函数:搜索框文本变化
void onSearch(const QString& _text);
//槽函数:点击下拉框选项
void itemClicked(int _index);
signals:
//信号:发送当前选中选项
void selectionChange(const QString _data);
private:
//下拉框
QListWidget* list_widget_;
//文本框,搜索框
QLineEdit* line_edit_, *search_bar_;
//搜索框显示标志
bool hidden_flag_;
//下拉框显示标志
bool show_flag_;
};
实现:
#include "multi_select_combobox.h"
MultiSelectComboBox::MultiSelectComboBox(QWidget *parent)
: QComboBox(parent)
, hidden_flag_(true)
, show_flag_(false)
{
list_widget_ = new QListWidget();
line_edit_ = new QLineEdit();
search_bar_ = new QLineEdit();
/*设置搜索框*/
QListWidgetItem* currentItem = new QListWidgetItem(list_widget_);
//设置搜索框提示信息
search_bar_->setPlaceholderText("Search.........");
//显示清除按钮
search_bar_->setClearButtonEnabled(true);
list_widget_->addItem(currentItem);
list_widget_->setItemWidget(currentItem, search_bar_);
/*设置文本框*/
//设为只读,因为该输入框只用来显示选中的选项,称为文本框更合适些
line_edit_->setReadOnly(true);
//把当前对象安装(或注册)为事件过滤器,当前也称为过滤器对象。事件过滤器通常在构造函数中进行注册。
line_edit_->installEventFilter(this);
//设置禁用样式,因为不受样式表控制,临时这样解决
line_edit_->setStyleSheet("QLineEdit:disabled{background:rgb(233,233,233);}");
this->setModel(list_widget_->model());
this->setView(list_widget_);
this->setLineEdit(line_edit_);
connect(search_bar_, SIGNAL(textChanged(const QString&)), this, SLOT(onSearch(const QString&)));
connect(this, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &MultiSelectComboBox::itemClicked);
}
MultiSelectComboBox::~MultiSelectComboBox()
{
}
void MultiSelectComboBox::hidePopup()
{
show_flag_ = false;
int width = this->width();
int height = this->height();
int x = QCursor::pos().x() - mapToGlobal(geometry().topLeft()).x() + geometry().x();
int y = QCursor::pos().y() - mapToGlobal(geometry().topLeft()).y() + geometry().y();
if (x >= 0 && x <= width && y >= this->height() && y <= height + this->height())
{
}
else
{
QComboBox::hidePopup();
}
}
void MultiSelectComboBox::addItem(const QString& _text, const QVariant& _variant /*= QVariant()*/)
{
Q_UNUSED(_variant);
QListWidgetItem* item = new QListWidgetItem(list_widget_);
QCheckBox* checkbox = new QCheckBox(this);
checkbox->setText(_text);
list_widget_->addItem(item);
list_widget_->setItemWidget(item, checkbox);
connect(checkbox, &QCheckBox::stateChanged, this, &MultiSelectComboBox::stateChange);
}
void MultiSelectComboBox::addItems(const QStringList& _text_list)
{
for (const auto& text_one : _text_list)
{
addItem(text_one);
}
}
QStringList MultiSelectComboBox::currentText()
{
QStringList text_list;
if (!line_edit_->text().isEmpty())
{
//以;为分隔符分割字符串
text_list = line_edit_->text().split(':');
}
return text_list;
}
int MultiSelectComboBox::count() const
{
int count = list_widget_->count() - 1;
if (count < 0)
{
count = 0;
}
return count;
}
void MultiSelectComboBox::SetSearchBarPlaceHolderText(const QString _text)
{
search_bar_->setPlaceholderText(_text);
}
void MultiSelectComboBox::SetPlaceHolderText(const QString& _text)
{
line_edit_->setPlaceholderText(_text);
}
void MultiSelectComboBox::ResetSelection()
{
int count = list_widget_->count();
for (int i = 1; i < count; i++)
{
//获取对应位置的QWidget对象
QWidget *widget = list_widget_->itemWidget(list_widget_->item(i));
//将QWidget对象转换成对应的类型
QCheckBox *check_box = static_cast<QCheckBox*>(widget);
check_box->setChecked(false);
}
}
void MultiSelectComboBox::clear()
{
line_edit_->clear();
list_widget_->clear();
QListWidgetItem* currentItem = new QListWidgetItem(list_widget_);
search_bar_->setPlaceholderText("Search.........");
search_bar_->setClearButtonEnabled(true);
list_widget_->addItem(currentItem);
list_widget_->setItemWidget(currentItem, search_bar_);
SetSearchBarHidden(hidden_flag_);
connect(search_bar_, SIGNAL(textChanged(const QString&)), this, SLOT(onSearch(const QString&)));
}
void MultiSelectComboBox::TextClear()
{
line_edit_->clear();
ResetSelection();
}
void MultiSelectComboBox::setCurrentText(const QString& _text)
{
int count = list_widget_->count();
for (int i = 1; i < count; i++)
{
//获取对应位置的QWidget对象
QWidget *widget = list_widget_->itemWidget(list_widget_->item(i));
//将QWidget对象转换成对应的类型
QCheckBox *check_box = static_cast<QCheckBox*>(widget);
if (_text.compare(check_box->text()))
check_box->setChecked(true);
}
}
void MultiSelectComboBox::setCurrentText(const QStringList& _text_list)
{
int count = list_widget_->count();
for (int i = 1; i < count; i++)
{
//获取对应位置的QWidget对象
QWidget *widget = list_widget_->itemWidget(list_widget_->item(i));
//将QWidget对象转换成对应的类型
QCheckBox *check_box = static_cast<QCheckBox*>(widget);
if (_text_list.contains(check_box->text()))
check_box->setChecked(true);
}
}
void MultiSelectComboBox::SetSearchBarHidden(bool _flag)
{
hidden_flag_ = _flag;
list_widget_->item(0)->setHidden(hidden_flag_);
}
bool MultiSelectComboBox::eventFilter(QObject *watched, QEvent *event)
{
//设置点击输入框也可以弹出下拉框
if (watched == line_edit_ && event->type() == QEvent::MouseButtonRelease && this->isEnabled())
{
showPopup();
return true;
}
return false;
}
void MultiSelectComboBox::wheelEvent(QWheelEvent *event)
{
//禁用QComboBox默认的滚轮事件
Q_UNUSED(event);
}
void MultiSelectComboBox::keyPressEvent(QKeyEvent *event)
{
QComboBox::keyPressEvent(event);
}
void MultiSelectComboBox::stateChange(int _row)
{
Q_UNUSED(_row);
QString selected_data("");
int count = list_widget_->count();
for (int i = 1; i < count; i++)
{
QWidget *widget = list_widget_->itemWidget(list_widget_->item(i));
QCheckBox *check_box = static_cast<QCheckBox*>(widget);
if (check_box->isChecked())
{
selected_data.append(check_box->text()).append(";");
}
}
selected_data.chop(1);
if (!selected_data.isEmpty())
{
line_edit_->setText(selected_data);
}
else
{
line_edit_->clear();
}
line_edit_->setToolTip(selected_data);
emit selectionChange(selected_data);
}
void MultiSelectComboBox::onSearch(const QString& _text)
{
for (int i = 1; i < list_widget_->count(); i++)
{
QCheckBox *check_box = static_cast<QCheckBox*>(list_widget_->itemWidget(list_widget_->item(i)));
//文本匹配则显示,反之隐藏
//Qt::CaseInsensitive模糊查询
if (check_box->text().contains(_text, Qt::CaseInsensitive))
list_widget_->item(i)->setHidden(false);
else
list_widget_->item(i)->setHidden(true);
}
}
void MultiSelectComboBox::itemClicked(int _index)
{
if (_index != 0)
{
QCheckBox *check_box = static_cast<QCheckBox*>(list_widget_->itemWidget(list_widget_->item(_index)));
check_box->setChecked(!check_box->isChecked());
}
}
总结
通过这次制作下拉复选框,深入的了解了QComboBox的组成。
存在问题:1、输入框不能输入中文。
2、输入框点击后,再次点击不能隐藏下拉框
3、点击item空白部分会直接隐藏下拉框
优化:样式优化,后续有时间优化后会继续更新。
如果此文帮助到你( ω ),动动小手点个赞可好O(∩_∩)O。
原创文章,转载请标明本文出处。
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦
边栏推荐
猜你喜欢
随机推荐
wordpress: 裁剪您的图片时发生错误
day12---接口和协议
推荐系统-排序层-精排模型:LR、GBDT、Wide&Deep、DCN、DIN、DIEN、MMOE、PLE
“唯一索引允许为空“ 的说法是不严谨的
数仓4.0(一)
积分商城系统设计
thop 使用心得
Eject stubborn hard drives with diskpart's offline command
ArcEngine(八)用IWorkspaceFactory加载矢量数据
熊市中预言机,牛市中的战斗机,藏宝计划起飞,坐稳扶好!
Evaluate:huggingface评价指标模块入门详细介绍
ArcEngine(六)用tool工具实现拉框放大缩小和平移
NFT到底有哪些实际用途?
【愚公系列】2022年07月 Go教学课程 026-结构体
ArcEngine (3) zoom in and zoom out through the MapControl control to achieve full-image roaming
使用pipreqs导出项目所需的requirements.txt(而非整个环境)
Dapr 与 NestJs ,实战编写一个 Pub & Sub 装饰器
Guava的Service
WPF 学习笔记《WPF样式基础》
【TPC-DS】25张表的详细介绍,SQL的查询特征