基本效果如下图:重写QComboBox实现能够多选的效果
代码实现
头文件
#include<QComboBox>
class MultiSelectComboBox :public QComboBox
{
Q_OBJECT
public:
explicit MultiSelectComboBox(QWidget *parent = 0);
public:
bool eventFilter(QObject*watched, QEvent*event) override;
void hidePopup() override;
void showPopup() override;
QStringList checkedItems() const;
void setCheckedItems(const QStringList& items);
public slots:
void onItemStateChanged();
void onInstallFilters();
void updateLineEditText(const QString &text);
};
源文件
#include <QMouseEvent>
#include <QKeyEvent>
#include <QAbstractItemView>
#include <QTimer>
#include <QLineEdit>
#include "MultiSelectComboBox.h"
MultiSelectComboBox::MultiSelectComboBox(QWidget *parent) : QComboBox(parent)
{
this->setEditable(true);
QTimer::singleShot(0, this, &MultiSelectComboBox::onInstallFilters); //延迟安装事件过滤器,确保界面初始化完成
connect(model(), &QAbstractItemModel::dataChanged, this, &MultiSelectComboBox::onItemStateChanged);
}
MultiSelectComboBox::~MultiSelectComboBox()
{
}
void MultiSelectComboBox::onInstallFilters()
{
if (this->view() && this->view()->viewport())
{
this->view()->viewport()->installEventFilter(this);
}
if (this->lineEdit())
{
this->lineEdit()->setReadOnly(true);
}
}
void MultiSelectComboBox::updateLineEditText(const QString &text)
{
Q_UNUSED(text);
this->lineEdit()->setText(checkedItems().join(";"));
}
bool MultiSelectComboBox::eventFilter(QObject* obj, QEvent* event)
{
if (obj == this->view()->viewport() && event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
QModelIndex index = view()->indexAt(mouseEvent->pos());
if (index.isValid())
{
bool checked = model()->data(index, Qt::CheckStateRole).toBool();
if (checked && checkedItems().count() == 1) // 确保至少选择一项
{
return true;
}
model()->setData(index, !checked, Qt::CheckStateRole);
return true;
}
}
return QComboBox::eventFilter(obj, event);
}
void MultiSelectComboBox::hidePopup()
{
setCurrentText(checkedItems().join(";"));
QComboBox::hidePopup();
}
void MultiSelectComboBox::showPopup()
{
QStringList selectedItems = currentText().split(";");
for (int i = 0; i < count(); ++i)
{
setItemData(i, selectedItems.contains(itemText(i)), Qt::CheckStateRole);
}
QComboBox::showPopup();
}
QStringList MultiSelectComboBox::checkedItems() const
{
QStringList items;
for (int i = 0; i < count(); ++i)
{
if (itemData(i, Qt::CheckStateRole).toBool())
{
items << itemText(i);
}
}
return items;
}
void MultiSelectComboBox::setCheckedItems(const QStringList& items)
{
for (int i = 0; i < count(); ++i)
{
setItemData(i, items.contains(itemText(i)), Qt::CheckStateRole);
}
setCurrentText(items.join(";"));
}
void MultiSelectComboBox::onItemStateChanged()
{
QStringList selectedItems = checkedItems();
QString newText = selectedItems.join(";");
if (currentText() != newText)
{
setCurrentText(newText);
}
}
使用方法
方式一:继承 MultiSelectComboBox
类,new一个对象
方式二:使用qt designer把QComboBox提升