头文件
#ifndef _CHECK_COMBOX_H
#define _CHECK_COMBOX_H
#include <QComboBox>
#include <QKeyEvent>
#include <QListView>
#include <QStandardItemModel>
class QLineEdit;
class QListView;
struct ItemInfo {
int idx;
QString str;
QVariant userData;
bool bChecked;
ItemInfo()
{
idx = -1;
str = QString("");
userData = QVariant();
bChecked = false;
}
};
// 事件过滤器
class KeyPressEater : public QObject {
Q_OBJECT
public:
KeyPressEater(QObject* parent = nullptr)
: QObject(parent)
{
}
~KeyPressEater() { }
signals:
void sigActivated(int idx);
protected:
bool eventFilter(QObject* obj, QEvent* event)
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Space) {
QListView* lstV = qobject_cast<QListView*>(obj);
if (nullptr != lstV) {
int idx = lstV->currentIndex().row();
if (-1 != idx) {
emit sigActivated(idx);
}
}
} else if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) {
return QObject::eventFilter(obj, event);
}
return true;
} else {
// standard event processing
return QObject::eventFilter(obj, event);
}
}
};
class MyComboBox : public QComboBox {
Q_OBJECT
public:
MyComboBox(QWidget* parent = Q_NULLPTR);
~MyComboBox();
// 添加item
void AddItem(const QString& str, bool bChecked = false, QVariant userData = QVariant());
void AddItems(const QList<ItemInfo>& lstItemInfo);
void AddItems(const QMap<QString, bool>& mapStrChk);
void AddItems(const QList<QString>& lstStr);
// 删除item
void RemoveItem(int idx);
// 清空item
void Clear();
// 获取选中的数据字符串列表
QStringList GetSelItemsText();
// 获取选中item的信息
QList<ItemInfo> GetSelItemsInfo();
// 获取item文本
QString GetItemText(int idx);
// 获取item信息
ItemInfo GetItemInfo(int idx);
signals:
// popup显示信号
void showingPopup();
// popup隐藏信号
void hidingPopup();
protected:
void showPopup();
// 重写QComboBox的hidePopup函数
// 目的选择过程中,不隐藏listview
void hidePopup();
virtual void mousePressEvent(QMouseEvent* event);
virtual void mouseReleaseEvent(QMouseEvent* event);
virtual void mouseMoveEvent(QMouseEvent* event);
private:
void UpdateText();
private slots:
void sltActivated(int idx);
private:
QLineEdit* pLineEdit;
QListView* pListView;
QStandardItemModel m_model;
};
#endif
实现
#include "ccheckcombobox.h"
#include <QDebug>
#include <QLineEdit>
#include <QMouseEvent>
MyComboBox::MyComboBox(QWidget* parent)
: QComboBox(parent)
{
pLineEdit = new QLineEdit(this);
pLineEdit->setReadOnly(true);
this->setLineEdit(pLineEdit);
this->lineEdit()->disconnect();
KeyPressEater* keyPressEater = new KeyPressEater(this);
pListView = new QListView(this);
pListView->installEventFilter(keyPressEater);
this->setView(pListView);
this->setModel(&m_model);
connect(this, SIGNAL(activated(int)), this, SLOT(sltActivated(int)));
connect(keyPressEater, SIGNAL(sigActivated(int)), this, SLOT(sltActivated(int)));
}
MyComboBox::~MyComboBox()
{
}
void MyComboBox::AddItem(const QString& str, bool bChecked /*= false*/, QVariant userData /*= QVariant()*/)
{
QStandardItem* item = new QStandardItem(str);
item->setCheckable(true);
item->setCheckState(bChecked ? Qt::Checked : Qt::Unchecked);
item->setData(userData, Qt::UserRole + 1);
m_model.appendRow(item);
UpdateText();
}
void MyComboBox::AddItems(const QList<ItemInfo>& lstItemInfo)
{
for (auto a : lstItemInfo) {
AddItem(a.str, a.bChecked, a.userData);
}
}
void MyComboBox::AddItems(const QMap<QString, bool>& mapStrChk)
{
for (auto it = mapStrChk.begin(); it != mapStrChk.end(); ++it) {
AddItem(it.key(), it.value());
}
}
void MyComboBox::AddItems(const QList<QString>& lstStr)
{
for (auto a : lstStr) {
AddItem(a, false);
}
}
void MyComboBox::RemoveItem(int idx)
{
m_model.removeRow(idx);
UpdateText();
}
void MyComboBox::Clear()
{
m_model.clear();
UpdateText();
}
QStringList MyComboBox::GetSelItemsText()
{
QStringList lst;
QString str = pLineEdit->text();
if (str.isEmpty()) {
return lst;
} else {
return pLineEdit->text().split(",");
}
}
QList<ItemInfo> MyComboBox::GetSelItemsInfo()
{
QList<ItemInfo> lstInfo;
for (int i = 0; i < m_model.rowCount(); i++) {
QStandardItem* item = m_model.item(i);
if (item->checkState() == Qt::Unchecked)
continue;
ItemInfo info;
info.idx = i;
info.str = item->text();
info.bChecked = true;
info.userData = item->data(Qt::UserRole + 1);
lstInfo << info;
}
return lstInfo;
}
QString MyComboBox::GetItemText(int idx)
{
if (idx < 0 || idx >= m_model.rowCount()) {
return QString("");
}
return m_model.item(idx)->text();
}
ItemInfo MyComboBox::GetItemInfo(int idx)
{
ItemInfo info;
if (idx < 0 || idx >= m_model.rowCount()) {
return info;
}
QStandardItem* item = m_model.item(idx);
info.idx = idx;
info.str = item->text();
info.bChecked = (item->checkState() == Qt::Checked);
info.userData = item->data(Qt::UserRole + 1);
return info;
}
void MyComboBox::showPopup()
{
emit showingPopup();
QComboBox::showPopup();
}
void MyComboBox::hidePopup()
{
int width = this->view()->width();
int height = this->view()->height();
int x = QCursor::pos().x() - mapToGlobal(geometry().topLeft()).x() + geometry().x();
int y = QCursor::pos().y() - mapToGlobal(geometry().topLeft()).y() + geometry().y();
QRect rectView(0, this->height(), width, height);
if (!rectView.contains(x, y)) {
emit hidingPopup();
QComboBox::hidePopup();
}
}
void MyComboBox::mousePressEvent(QMouseEvent* event)
{
QComboBox::mousePressEvent(event);
event->accept();
}
void MyComboBox::mouseReleaseEvent(QMouseEvent* event)
{
QComboBox::mouseReleaseEvent(event);
event->accept();
}
void MyComboBox::mouseMoveEvent(QMouseEvent* event)
{
QComboBox::mouseMoveEvent(event);
event->accept();
}
void MyComboBox::UpdateText()
{
QStringList lstTxt;
for (int i = 0; i < m_model.rowCount(); ++i) {
QStandardItem* item = m_model.item(i);
if (item->checkState() == Qt::Unchecked)
continue;
lstTxt << item->text();
}
pLineEdit->setText(lstTxt.join(","));
pLineEdit->setToolTip(lstTxt.join("\n"));
}
void MyComboBox::sltActivated(int idx)
{
QStandardItem* item = m_model.item(idx);
if (nullptr == item)
return;
Qt::CheckState state = (item->checkState() == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
item->setCheckState(state);
UpdateText();
}
使用
MyComboBox combox;
QStringList lstStr;
for (int i = 0; i < 10; ++i) {
lstStr << QString("item %1").arg(i);
}
combox.AddItems(lstStr);