QtableWidget设置表头点击事件,显示筛选框,实现类似excel的表头筛选功能;
通过重写eventFilter事件过滤方法,获取鼠标点击的事件(含点击表格的空白处)
效果图
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTableWidget>
#include <QToolButton>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QEvent>
#include "FilterWidget.h"
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
//初始化
void Init();
//插入测试数据
void InsertDatas();
//筛选
void filter(int col, QStringList showList);
//关闭筛选框
void closeFilterWidget();
//事件过滤
bool eventFilter(QObject *obj, QEvent *e);
//初始化map
void initMap();
private slots:
//表头点击槽函数
void onHeaderClicked(int);
private:
QTableWidget *m_tableWidget = nullptr;
//筛选框
FilterWidget* m_filterWidget = nullptr;
//列号,显示的元素
QMap<int, QStringList> m_map;
};
#endif // WIDGET_H
Widget.cpp
#include "widget.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QRadioButton>
#include <QMessageBox>
#include <QSet>
#include <QMouseEvent>
#pragma execution_character_set("utf-8")
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//初始化
Init();
//插入测试数据
InsertDatas();
QVBoxLayout* lay = new QVBoxLayout(this);
lay->setMargin(0);
lay->setSpacing(0);
setLayout(lay);
lay->addWidget(m_tableWidget);
//注册事件过滤
m_tableWidget->viewport()->installEventFilter(this);
}
Widget::~Widget()
{
if (m_filterWidget != nullptr)
{
delete m_filterWidget;
m_filterWidget = nullptr;
}
}
//初始化表格
void Widget::Init()
{
m_tableWidget = new QTableWidget(this);
//表头字体居中
m_tableWidget->horizontalHeader()->setDefaultAlignment(Qt::AlignHCenter);
//自适应宽度
m_tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
//使行列头自适应宽度,最后一列将会填充空白部分
m_tableWidget->horizontalHeader()->setStretchLastSection(true);
//设置行选中
m_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
//选中多行,可以使用shift,ctrl
//SingleSelection-单选
//MultiSelection-多选
//ExtendedSelection-支持shift,ctrl和Ctr+A操作
m_tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
//禁止编辑
m_tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
//隐藏垂直表头
//m_tableWidget->verticalHeader()->hide();
m_tableWidget->setColumnWidth(0, 150);
m_tableWidget->setColumnWidth(1, 80);
m_tableWidget->setColumnWidth(2, 80);
m_tableWidget->setColumnWidth(3, 250);
m_tableWidget->setColumnWidth(4, 50);
QStringList headerLabels;
headerLabels << QString("列1") << QString("列2") << QString("列3") << QString("列4") << QString("列5");
m_tableWidget->setColumnCount(headerLabels.size());
m_tableWidget->setHorizontalHeaderLabels(headerLabels);
//表头点击
connect(m_tableWidget->horizontalHeader()
, SIGNAL(sectionClicked(int))
,this
, SLOT(onHeaderClicked(int)));
}
//插入测试数据
void Widget::InsertDatas()
{
for (int i = 0; i < 2; i++)
{
int row = m_tableWidget->rowCount();
m_tableWidget->insertRow(row);
m_tableWidget->setItem(row, 0, new QTableWidgetItem(QString("1")));
m_tableWidget->setItem(row, 1, new QTableWidgetItem(QString("1")));
m_tableWidget->setItem(row, 2, new QTableWidgetItem(QString("1")));
m_tableWidget->setItem(row, 3, new QTableWidgetItem(QString("1")));
m_tableWidget->setItem(row, 4, new QTableWidgetItem(QString("1")));
}
for (int i = 0; i < 2; i++)
{
int row = m_tableWidget->rowCount();
m_tableWidget->insertRow(row);
m_tableWidget->setItem(row, 0, new QTableWidgetItem(QString("2")));
m_tableWidget->setItem(row, 1, new QTableWidgetItem(QString("2")));
m_tableWidget->setItem(row, 2, new QTableWidgetItem(QString("2")));
m_tableWidget->setItem(row, 3, new QTableWidgetItem(QString("2")));
m_tableWidget->setItem(row, 4, new QTableWidgetItem(QString("2")));
}
for (int i = 0; i < 2; i++)
{
int row = m_tableWidget->rowCount();
m_tableWidget->insertRow(row);
m_tableWidget->setItem(row, 0, new QTableWidgetItem(QString("1")));
m_tableWidget->setItem(row, 1, new QTableWidgetItem(QString("3")));
m_tableWidget->setItem(row, 2, new QTableWidgetItem(QString("3")));
m_tableWidget->setItem(row, 3, new QTableWidgetItem(QString("3")));
m_tableWidget->setItem(row, 4, new QTableWidgetItem(QString("2")));
}
//初始化map
initMap();
}
//初始化map
void Widget::initMap()
{
for (int col = 0; col < m_tableWidget->columnCount(); col++)
{
QStringList strList;
for (int row = 0; row < m_tableWidget->rowCount(); row++)
{
QString strItem = m_tableWidget->item(row, col)->text();
strList.append(strItem);
}
m_map[col] = strList;
}
}
//筛选
void Widget::filter(int col, QStringList showList)
{
m_map[col] = showList;
for (int i = 0; i < m_tableWidget->rowCount(); i++)
{
bool hidden = false;
//遍历map
for each (int v_col in m_map.keys())
{
QString strItem = m_tableWidget->item(i, v_col)->text();
if (!m_map.value(v_col).contains(strItem))
{
hidden = true;
break;
}
}
m_tableWidget->setRowHidden(i, hidden);
}
}
//表头点击槽函数
void Widget::onHeaderClicked(int col)
{
//所有item
QSet<QString> items;
//显示的item
QSet<QString> showItems;
//行数
int rows = m_tableWidget->rowCount();
//遍历列表
for (int i = 0; i < rows; i++)
{
QString strItem = m_tableWidget->item(i, col)->text();
items.insert(strItem);
if (m_map.value(col).contains(strItem))
{
showItems.insert(strItem);
}
}
//转为QStringList
QStringList strItems;
QStringList strShowItems;
for each (QString var in items)
{
strItems.append(var);
}
for each (QString var in showItems)
{
strShowItems.append(var);
}
//关闭筛选框
closeFilterWidget();
//新建筛选框
m_filterWidget = new FilterWidget(strItems, strShowItems, col, m_tableWidget);
m_filterWidget->exec(m_tableWidget->mapFromGlobal(cursor().pos()));
}
//事件过滤
bool Widget::eventFilter(QObject *target, QEvent *event)
{
QMouseEvent *e = static_cast<QMouseEvent *>(event);
if (e == nullptr)
{
return QWidget::eventFilter(target, event);
}
if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease)
{
closeFilterWidget();
}
return QWidget::eventFilter(target, event);
}
//关闭筛选框
void Widget::closeFilterWidget()
{
//清空筛选框
if (m_filterWidget != nullptr)
{
QStringList showList = m_filterWidget->getShowList();
filter(m_filterWidget->getColumn(), showList);
delete m_filterWidget;
m_filterWidget = nullptr;
}
}
FilterWidget.h
#pragma once
#include <QWidget>
#include <QListWidget>
#include <QListWidgetItem>
#include <QList>
#include <QCheckBox>
#include <QSet>
class FilterWidget :
public QWidget
{
public:
FilterWidget(QStringList Items, QStringList showItems, int col, QWidget *parent = 0);
~FilterWidget();
//获取要显示的列表
QStringList getShowList();
//获取列号
int getColumn();
//显示
void exec(const QPoint &pos);
private slots:
//勾选状态更改
void slot_stateChanged();
private:
QListWidget* m_ListWidget = nullptr;
//要显示的项
QStringList m_showList;
//列号
int m_col;
};
FilterWidget.cpp
#include "FilterWidget.h"
#include <QVBoxLayout>
#include <QEventLoop>
//Items:所有项
//showItems:显示的项
//col:列号
FilterWidget::FilterWidget(QStringList Items, QStringList showItems, int col, QWidget *parent/*=0*/):
QWidget(parent),
m_col(col)
{
this->setFixedWidth(50);
this->setFixedHeight(100);
m_ListWidget = new QListWidget(this);
QVBoxLayout* lay = new QVBoxLayout(this);
lay->setMargin(0);
lay->setSpacing(0);
setLayout(lay);
for each (QString var in Items)
{
QCheckBox* checkBox = new QCheckBox(this);
checkBox->setText(var);
if (showItems.contains(var))
{
m_showList.append(var);
checkBox->setChecked(true);
}
connect(checkBox, &QCheckBox::stateChanged, this, &FilterWidget::slot_stateChanged);
QListWidgetItem *item = new QListWidgetItem();
m_ListWidget->addItem(item);
m_ListWidget->setItemWidget(item,checkBox);
}
lay->addWidget(m_ListWidget);
}
FilterWidget::~FilterWidget()
{
}
QStringList FilterWidget::getShowList()
{
return m_showList;
}
int FilterWidget::getColumn()
{
return m_col;
}
void FilterWidget::exec(const QPoint & pos)
{
setAttribute(Qt::WA_ShowModal, true);
move(pos);
show();
QRect rect = geometry();
QEventLoop loop;
loop.exec();
}
void FilterWidget::slot_stateChanged()
{
m_showList.clear();
//遍历
for (int i = 0; i < m_ListWidget->count(); i++)
{
//先获取QListWidgetItem
QListWidgetItem *item = m_ListWidget->item(i);
//找到第i个Item对应的CheckBox
QCheckBox *checkBox = static_cast<QCheckBox *>(m_ListWidget->itemWidget(item));
if (checkBox->isChecked())
m_showList.append(checkBox->text());
}
}