头文件
#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_OBJECTpublic: 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_OBJECTpublic: 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);