十五、帶複選框的ComboBox(自定義QComboBox)

一、效果圖

在這裏插入圖片描述

二、代碼實現

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();
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章