【Qt】QTableView添加下拉框过滤条件

实现通过带复选框的下拉框来为表格添加过滤条件

带复选框的下拉框

.h文件

cpp 复制代码
#pragma once
#include <QCheckBox>
#include <QComboBox>
#include <QEvent>
#include <QLineEdit>
#include <QListWidget>

class TableComboBox : public QComboBox
{
    Q_OBJECT

public:
    TableComboBox(QWidget* parent = NULL);
    ~TableComboBox();

    // 隐藏下拉框
    virtual void hidePopup();

    // 添加一条选项
    void addItem(const QString& _text, const QVariant& _variant = QVariant());

    // 添加多条选项
    void addItems(const QStringList& _text_list);

    // 返回当前选中选项
    QStringList currentText();

    // 返回当前选项条数
    int count() const;

    // 设置搜索框默认文字
    void SetSearchBarPlaceHolderText(const QString _text);

    // 设置文本框默认文字
    void SetPlaceHolderText(const QString& _text);

    // 下拉框状态恢复默认
    void ResetSelection();

    // 清空所有内容
    void clear();

    // 文本框内容清空
    void TextClear();

    // 设置选中文本--单
    void setCurrentText(const QString& _text);

    // 设置选中文本--多
    void setCurrentText(const QStringList& _text_list);

    // 设置搜索框是否禁用
    void SetSearchBarHidden(bool _flag);

protected:
    // 事件过滤器
    virtual bool eventFilter(QObject* watched, QEvent* event);

    // 滚轮事件
    virtual void wheelEvent(QWheelEvent* event);

    // 按键事件
    virtual void keyPressEvent(QKeyEvent* event);

private slots:

    // 文本框文本变化
    void stateChange(int _row);

    // 点击下拉框选项
    void itemClicked(int _index);

signals:

    // 发送当前选中选项
    void selectionChange(const QString _data);

private:
    // 下拉框
    QListWidget* pListWidget;
    // 文本框,搜索框
    QLineEdit *pLineEdit, *pSearchBarEdit;
    // 搜索框显示标志
    bool isHidden;
    // 下拉框显示标志
    bool isShow;
};

.cpp文件

cpp 复制代码
#include "PowerTableComboBox.h"

#include <QMessageBox>

#define FREEPTR(p) \
    if (p != NULL) \
    {              \
        delete p;  \
        p = NULL;  \
    }

TableComboBox::TableComboBox(QWidget* parent)
    : QComboBox(parent)
    , isHidden(true)
    , isShow(false)
{
    pListWidget = new QListWidget();
    pLineEdit = new QLineEdit();
    pSearchBarEdit = new QLineEdit();

    QListWidgetItem* currentItem = new QListWidgetItem(pListWidget);
    pSearchBarEdit->setPlaceholderText("搜索...");
    pSearchBarEdit->setClearButtonEnabled(true);
    pListWidget->addItem(currentItem);
    pListWidget->setItemWidget(currentItem, pSearchBarEdit);

    pLineEdit->setReadOnly(true);
    pLineEdit->installEventFilter(this);
    pLineEdit->setStyleSheet("QLineEdit:disabled{background:rgb(233,233,233);}");

    this->setModel(pListWidget->model());
    this->setView(pListWidget);
    this->setLineEdit(pLineEdit);
    connect(this, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TableComboBox::itemClicked);
}

TableComboBox::~TableComboBox()
{
    FREEPTR(pLineEdit);
    FREEPTR(pSearchBarEdit);
}

void TableComboBox::hidePopup()
{
    isShow = false;
    int width = this->width();
    int height = this->height();
    int x = QCursor::pos().x() - mapToGlobal(geometry().topLeft()).x() + geometry().x();
    int y = QCursor::pos().y() - mapToGlobal(geometry().topLeft()).y() + geometry().y();
    if (x >= 0 && x <= width && y >= this->height() && y <= height + this->height())
    {
    }
    else
    {
        QComboBox::hidePopup();
    }
}

void TableComboBox::addItem(const QString& _text, const QVariant& _variant)
{
    Q_UNUSED(_variant);
    QListWidgetItem* item = new QListWidgetItem(pListWidget);
    QCheckBox* checkbox = new QCheckBox(this);
    checkbox->setText(_text);
    pListWidget->setItemWidget(item, checkbox);
    pListWidget->addItem(item);
    connect(checkbox, &QCheckBox::stateChanged, this, &TableComboBox::stateChange);
    checkbox->setChecked(true);
}

void TableComboBox::addItems(const QStringList& _text_list)
{
    for (const auto& text_one : _text_list)
    {
        addItem(text_one);
    }
}

QStringList TableComboBox::currentText()
{
    QStringList text_list;
    if (!pLineEdit->text().isEmpty())
    {
        // 以空格为分隔符分割字符串
        text_list = pLineEdit->text().split(' ');
    }
    return text_list;
}

int TableComboBox::count() const
{
    int count = pListWidget->count() - 1;
    if (count < 0)
    {
        count = 0;
    }
    return count;
}

void TableComboBox::SetSearchBarPlaceHolderText(const QString _text)
{
    pSearchBarEdit->setPlaceholderText(_text);
}

void TableComboBox::SetPlaceHolderText(const QString& _text)
{
    pLineEdit->setPlaceholderText(_text);
}

void TableComboBox::ResetSelection()
{
    int count = pListWidget->count();
    for (int i = 1; i < count; i++)
    {
        QWidget* widget = pListWidget->itemWidget(pListWidget->item(i));
        QCheckBox* check_box = static_cast<QCheckBox*>(widget);
        check_box->setChecked(false);
    }
}

void TableComboBox::clear()
{
    pLineEdit->clear();
    pListWidget->clear();
    QListWidgetItem* currentItem = new QListWidgetItem(pListWidget);
    pSearchBarEdit->setPlaceholderText("搜索...");
    pSearchBarEdit->setClearButtonEnabled(true);
    pListWidget->addItem(currentItem);
    pListWidget->setItemWidget(currentItem, pSearchBarEdit);
    SetSearchBarHidden(isHidden);
}

void TableComboBox::TextClear()
{
    pLineEdit->clear();
    ResetSelection();
}

void TableComboBox::setCurrentText(const QString& _text)
{
    int count = pListWidget->count();
    for (int i = 1; i < count; i++)
    {
        QWidget* widget = pListWidget->itemWidget(pListWidget->item(i));
        QCheckBox* check_box = static_cast<QCheckBox*>(widget);
        if (_text.compare(check_box->text()))
            check_box->setChecked(true);
    }
}

void TableComboBox::setCurrentText(const QStringList& _text_list)
{
    int count = pListWidget->count();
    for (int i = 1; i < count; i++)
    {
        QWidget* widget = pListWidget->itemWidget(pListWidget->item(i));
        QCheckBox* check_box = static_cast<QCheckBox*>(widget);
        if (_text_list.contains(check_box->text()))
            check_box->setChecked(true);
    }
}

void TableComboBox::SetSearchBarHidden(bool _flag)
{
    isHidden = _flag;
    pListWidget->item(0)->setHidden(isHidden);
}

bool TableComboBox::eventFilter(QObject* watched, QEvent* event)
{
    if (watched == pLineEdit && event->type() == QEvent::MouseButtonRelease && this->isEnabled())
    {
        showPopup();
        return true;
    }
    return false;
}

void TableComboBox::wheelEvent(QWheelEvent* event)
{
    Q_UNUSED(event);
}

void TableComboBox::keyPressEvent(QKeyEvent* event)
{
    QComboBox::keyPressEvent(event);
}

void TableComboBox::stateChange(int _row)
{
    Q_UNUSED(_row);
    QString selected_data("");
    int count = pListWidget->count();
    for (int i = 1; i < count; i++)
    {
        QWidget* widget = pListWidget->itemWidget(pListWidget->item(i));
        QCheckBox* check_box = static_cast<QCheckBox*>(widget);
        if (check_box->isChecked())
        {
        	// 添加空格做为分割符
            selected_data.append(check_box->text()).append(" ");
        }
    }
    selected_data.chop(1);
    if (!selected_data.isEmpty())
    {
        pLineEdit->setText(selected_data);
    }
    else
    {
        pLineEdit->clear();
    }

    // 文字从最左边开始显示
    pLineEdit->setToolTip(selected_data);
    pLineEdit->setSelection(0, 0);
    pLineEdit->setCursorPosition(0);

    emit selectionChange(selected_data);
}

void TableComboBox::itemClicked(int _index)
{
    if (_index != 0)
    {
        QCheckBox* check_box = static_cast<QCheckBox*>(pListWidget->itemWidget(pListWidget->item(_index)));
        check_box->setChecked(!check_box->isChecked());
    }
}

表格过滤器代理类

cpp 复制代码
class TableProxyModel : public QSortFilterProxyModel
{
public:
    TableProxyModel (QObject* parent = nullptr)
        : QSortFilterProxyModel(parent)
    {}

protected:
    bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override
    {
        QModelIndex targetTypeIndex = sourceModel()->index(source_row, 0, source_parent);
        QModelIndex boomNameIndex = sourceModel()->index(source_row, 1, source_parent);
        QModelIndex destructionDegreeIndex = sourceModel()->index(source_row, 2, source_parent);
        QString typeText = sourceModel()->data(targetTypeIndex).toString();
        QString nameText = sourceModel()->data(boomNameIndex).toString();
        int levelText = sourceModel()->data(destructionDegreeIndex).toInt();

        if (!isFilter)
        {
            return true;
        }

        bool matchType = false;
        bool matchName = false;
        bool levelText = false;
        for (QString type : sType)
        {
            if (typeText == type)
            {
                matchType = true;
                break;
            }
        }

        for (QString name : sName)
        {
            if (nameText == name)
            {
                matchName = true;
                break;
            }
        }

        for (int level: nLevelVec)
        {
            if (levelText == level)
            {
                matchLevel = true;
                break;
            }
        }

        if (matchLevel && matchName && matchType)
        {
            return true;
        }

        return false;
    }

public:
    QStringList sType;
    QStringList sName;
    QVector<int> nLevelVec;
    bool isFilter = false;
};

表格设置代理关联下拉框内容变更

添加代理

cpp 复制代码
    tableView = new QTableView;
    proxyModel = new TableProxyModel;

    // 设置过滤规则来执行过滤
    proxyModel->setFilterRole(Qt::DisplayRole);
    proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    proxyModel->setSourceModel(model);
    tableView->setModel(proxyModel);

下拉框关联表格代理

  1. 通过信号与槽关联
cpp 复制代码
 connect(typeBox, &TableComboBox::selectionChange, this, &ShowTableView::filterBtnClick);
  1. 获取下拉框内容传到代理类做过滤
cpp 复制代码
void ShowTableView::filterBtnClick(QString)
{
    // 复位
    proxyModel->isFilter = true;
    proxyModel->sType.clear();
    proxyModel->sName.clear();
    proxyModel->nLevelVec.clear();

    // 获取筛选条件
    proxyModel->sType = typeBox->currentText();
    proxyModel->sName= boomNameBox->currentText();
    for (QString level: levelBox->currentText())
    {
        proxyModel->nLevelVec.push_back(level.toInt());
    }
    proxyModel->setFilterFixedString("");
}
  1. 取消过滤,复位
cpp 复制代码
void ShowTableView::noFilterBtnClick()
{
    proxyModel->isFilter = false;
    proxyModel->setFilterFixedString("");
}

截图

  1. 过滤前
  2. 过滤后
相关推荐
Watermelo6174 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
半盏茶香1 小时前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
Evand J2 小时前
LOS/NLOS环境建模与三维TOA定位,MATLAB仿真程序,可自定义锚点数量和轨迹点长度
开发语言·matlab
LucianaiB2 小时前
探索CSDN博客数据:使用Python爬虫技术
开发语言·爬虫·python
Ronin3052 小时前
11.vector的介绍及模拟实现
开发语言·c++
计算机学长大白3 小时前
C中设计不允许继承的类的实现方法是什么?
c语言·开发语言
PieroPc4 小时前
Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印
开发语言·python·excel
2401_857439697 小时前
SSM 架构下 Vue 电脑测评系统:为电脑性能评估赋能
开发语言·php
SoraLuna7 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
xlsw_7 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis