一、效果图
二、代码实现
MenuItem.h
#ifndef MENUITEM_H
#define MENUITEM_H
#include <QObject>
class MenuItem
{
public:
MenuItem(int menuId, const QString &menuName, bool isChecked = false);
MenuItem();
//拷贝构造函数,载遍历类集合时,需要使用
MenuItem(const MenuItem &menuItem);
int getMenuId() const;
void setMenuId(int value);
QString getMenuName() const;
void setMenuName(const QString &value);
bool getIsChecked() const;
void setIsChecked(bool value);
private:
int menuId;
QString menuName;
bool isChecked;
};
#endif // MENUITEM_H
MenuItem.cpp
#include "menuitem.h"
MenuItem::MenuItem(int menuId, const QString &menuName, bool isChecked)
{
this->menuId = menuId;
this->menuName = menuName;
this->isChecked = isChecked;
}
MenuItem::MenuItem()
{
this->menuId = -1;
this->menuName = QString("");
this->isChecked = false;
}
MenuItem::MenuItem(const MenuItem &menuItem)
{
this->menuId = menuItem.getMenuId();
this->menuName = menuItem.getMenuName();
this->isChecked = menuItem.getIsChecked();
}
int MenuItem::getMenuId() const
{
return menuId;
}
void MenuItem::setMenuId(int value)
{
menuId = value;
}
QString MenuItem::getMenuName() const
{
return menuName;
}
void MenuItem::setMenuName(const QString &value)
{
menuName = value;
}
bool MenuItem::getIsChecked() const
{
return isChecked;
}
void MenuItem::setIsChecked(bool value)
{
isChecked = value;
}
MultiComBox.h
#ifndef MULTICOMBOX_H
#define MULTICOMBOX_H
#include <QWidget>
#include <QComboBox>
class MenuItem;
class QLineEdit;
class QListView;
class QStandardItemModel;
class MultiComBox : public QComboBox
{
Q_OBJECT
public:
MultiComBox(QWidget *parent = Q_NULLPTR);
~MultiComBox();
//添加 item
void addItems(QList<MenuItem*> menus);
/**
* @brief 移除 Item
* @param row 行数
*/
void removeItem(int row);
void clear();
//获取选中的字符串
QStringList getItemsText();
//获取选中项的 id 集合
QList<int> getItemIds();
signals:
//选中 item 时,发送信号
void sigActivated(int row);
protected:
void hidePopup() Q_DECL_OVERRIDE;
bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE;
private:
QList<MenuItem> menus;
QLineEdit *pLineEdit;
QListView *pListView;
QStandardItemModel *itemModel;
private:
//更新选中字符串
void updateText();
public slots:
//响应单击 item
void sltActivated(int row);
};
#endif // MULTICOMBOX_H
MultiComBox.cpp
#include "multicombox.h"
#include "menuitem.h"
#include "../app.h"
#include <QLineEdit>
#include <QListView>
#include <QStandardItemModel>
#include <QMouseEvent>
MultiComBox::MultiComBox(QWidget *parent) : QComboBox(parent)
{
//为 ComBox 设置编辑框
pLineEdit = new QLineEdit(this);
pLineEdit->setReadOnly(true);
this->setLineEdit(pLineEdit);
//设置 ComBox 下拉界面
pListView = new QListView(this);
pListView->installEventFilter(this);
this->setView(pListView);
//设置 ComBox 数据模型
itemModel = new QStandardItemModel(this);
this->setModel(itemModel);
connect(this, SIGNAL(activated(int)), this, SLOT(sltActivated(int)));
}
MultiComBox::~MultiComBox()
{
}
void MultiComBox::addItems(QList<MenuItem*> menus)
{
QStandardItem *newItem;
for (MenuItem *menuItem : menus) {
newItem = new QStandardItem(menuItem->getMenuName());
//不加这一段代码,不出现单选框
newItem->setCheckable(Qt::Checked);
newItem->setCheckable(menuItem->getIsChecked() ? Qt::Checked : Qt::Unchecked);
newItem->setData(menuItem->getMenuId());
itemModel->appendRow(newItem);
}
updateText();
}
void MultiComBox::removeItem(int row)
{
itemModel->removeRow(row);
updateText();
}
void MultiComBox::clear()
{
itemModel->clear();
updateText();
}
QStringList MultiComBox::getItemsText()
{
QStringList strs;
QString str = pLineEdit->text();
if (!str.isEmpty()) {
strs = str.split(App::SEPERATOR);
}
return strs;
}
QList<int> MultiComBox::getItemIds()
{
QList<int> ids;
for (int i=0; i<itemModel->rowCount(); i++) {
QStandardItem *item = itemModel->item(i);
if (item->checkState() == Qt::Checked) {
ids << item->data().toInt();
}
}
return ids;
}
/**
* 目标:通过判断鼠标是否还在 ComBox 下拉框区域,来判断,是否隐藏下拉框
*/
void MultiComBox::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)) {
QComboBox::hidePopup();
}
}
bool MultiComBox::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton) {
QListView *listView = qobject_cast<QListView*>(watched);
if (nullptr != listView) {
int row = listView->currentIndex().row();
if (row != -1) {
sltActivated(row);
}
}
return true;
}
}
return QComboBox::eventFilter(watched, event);
}
void MultiComBox::updateText()
{
QStringList strs;
for (int i=0; i<itemModel->rowCount(); i++) {
QStandardItem *item = itemModel->item(i);
if (item->checkState() == Qt::Checked) {
strs << item->text();
}
}
pLineEdit->setText(strs.join(App::SEPERATOR));
pLineEdit->setToolTip(strs.join("\n"));
}
void MultiComBox::sltActivated(int row)
{
QStandardItem *item = itemModel->item(row);
Qt::CheckState checkState = item->checkState() == Qt::Checked ? Qt::Unchecked : Qt::Checked;
item->setCheckState(checkState);
updateText();
}