文章目录
1 简述
QTableWidget
是 Qt 框架中用于显示二维表格数据的组件,表格中的每个单元格都是 QTableWidgetItem 对象,可以用它来设置和读取单元格中的内容和样式。
- 在实际开发中常常需要通过自定义 QTableWidgetItem 来创造更加丰富多彩的单元格内容。
- 简单易用、功能齐全以及可高度自定义的优点很适合处理中等规模的数据。
开发环境
- 系统:Window10
- Qt版本:5.14.2
- 编译器:MinGW_64
2 实现效果
3 实现步骤
3.1 自定义CustomizeHeaderView类
这个类主要是在headerView上加一个QToolButton控件用来批量选中所有项以及绘制表项。
customizeheaderview.h
文件
class CustomizeHeaderView : public QHeaderView
{
Q_OBJECT
public:
explicit CustomizeHeaderView(Qt::Orientation orientation, QWidget *parent = nullptr);
void setHeaderViewWidget(int logicalIndex, QWidget *widget);
void setSectionHidden(int logicalIndex, bool hide);
protected:
virtual void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
private:
QMap<int, QWidget*> headerViewWidgets;
};
customizeheaderview.cpp
源文件
void CustomizeHeaderView::setHeaderViewWidget(int logicalIndex, QWidget *widget)
{
headerViewWidgets.insert(logicalIndex, widget);
if (widget != nullptr)
widget->setParent(this);
}
void CustomizeHeaderView::setSectionHidden(int logicalIndex, bool hide)
{
// 先调用父类函数实现默认功能
QHeaderView::setSectionHidden(logicalIndex, hide);
// 如果该索引设置了控件,则同步隐藏/显示控件
if (headerViewWidgets.contains(logicalIndex) &&
headerViewWidgets.value(logicalIndex) != nullptr)
{
headerViewWidgets.value(logicalIndex)->setHidden(hide);
}
}
// 该函数在QHeaderView类中是const成员函数,派生类重写该虚函数时要保留const,否则基类不会调用
void CustomizeHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
QHeaderView::paintSection(painter, rect, logicalIndex);
if (headerViewWidgets.contains(logicalIndex) &&
headerViewWidgets.value(logicalIndex) != nullptr)
{
headerViewWidgets.value(logicalIndex)->setGeometry(rect);
headerViewWidgets.value(logicalIndex)->setVisible(true);
}
}
3.2 自定义MyTableDelegate委托类
该类有一个枚举用于标识编号以及批量选中,并通过重写paint()函数绘制编号以及全选项。
enum class DelegateColumnIndex
{
NumberColumn, // 编号
BatchCheckColumn, // 批量选中
};
mytabledelegate.cpp
源文件
MyTableDelegate::MyTableDelegate(QObject *parent)
: QStyledItemDelegate{parent}
{
checkedPix.load(":/icons/checked.png");
checkedPix = checkedPix.scaled(QSize(26, 26), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
uncheckedPix.load(":/icons/unchecked.png");
uncheckedPix = uncheckedPix.scaled(QSize(26, 26), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
void MyTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyledItemDelegate::paint(painter, option, index);
if (index.column() == int(DelegateColumnIndex::NumberColumn)) {
qApp->style()->drawItemText(painter, option.rect, Qt::AlignCenter, QApplication::palette(), true, QString("%1").arg(index.row() + 1));
} else if (index.column() == int(DelegateColumnIndex::BatchCheckColumn)) {
if (index.data(Qt::UserRole).toBool()) {
qApp->style()->drawItemPixmap(painter, option.rect, Qt::AlignCenter, checkedPix);
} else {
qApp->style()->drawItemPixmap(painter, option.rect, Qt::AlignCenter, uncheckedPix);
}
}
}
3.3 MyTableWidget类
该类将搭配MyTableDelegate委托类和CustomizeHeaderView类一起,主要实现对数据项的一些设置和获取的操作,还有对表格控件的一些初始化操作。
mytablewidget.cpp
源文件
void MyTableWidget::setItemText(int row, int column, const QString &text, Qt::Alignment alignment)
{
QTableWidgetItem *item = this->item(row, column);
if (item) {
item->setText(text);
item->setTextAlignment(alignment);
} else {
item = new QTableWidgetItem(text);
item->setTextAlignment(alignment);
this->setItem(row, column, item);
}
}
// 设置item指定角色对应的数据
void MyTableWidget::setItemData(int row, int column, QVariant variant, Qt::ItemDataRole role)
{
QTableWidgetItem *item = this->item(row, column);
if (item) {
item->setData(role, variant);
} else {
item = new QTableWidgetItem;
item->setData(role, variant);
this->setItem(row, column, item);
}
}
void MyTableWidget::initTable()
{
this->setFocusPolicy(Qt::NoFocus); // 无焦点
this->setShowGrid(false); // 不显示网格线
this->verticalHeader()->setVisible(false); // 隐藏垂直表头
this->horizontalHeader()->setVisible(false);
this->setEditTriggers(QAbstractItemView::NoEditTriggers); // 表格不可编辑
this->setSelectionMode(QAbstractItemView::ExtendedSelection); // 设置选中的模式
this->setSelectionBehavior(QAbstractItemView::SelectRows); // 设置选中的行为 整行选中
}
3.4 主界面
- 在主界面初始化自定义表格控件一些属性
void Widget::initTableWidget()
{
ui->tableWidget->setRowCount(12);
ui->tableWidget->setColumnCount(6);
m_tableDelegate = new MyTableDelegate(this);
ui->tableWidget->setItemDelegate(m_tableDelegate);
m_headerView = new CustomizeHeaderView(Qt::Horizontal, this);
ui->tableWidget->setHorizontalHeader(m_headerView);
QList<int> columnWidths;
columnWidths << 50 << 30 << 300 << 170 << 100 << 120;
for (int i = 0; i < 6; ++i) {
ui->tableWidget->setColumnWidth(i, columnWidths.at(i));
}
ui->tableWidget->verticalHeader()->setDefaultSectionSize(50); // 设置行高
connect(ui->tableWidget, &MyTableWidget::cellClicked, this, &Widget::onTableCellClicked);
currentSortColumn = 4;
currentSortOrder = Qt::DescendingOrder;
m_headerView->setVisible(true);
m_headerView->setSortIndicatorShown(true); // 显示排序指示符
m_headerView->setSortIndicator(currentSortColumn, currentSortOrder);
m_headerView->setSectionsClickable(true);
// 水平表头全选按钮
m_batchCheckBtn = new QToolButton(m_headerView);
m_batchCheckBtn->setFixedSize(30, 30);
m_batchCheckBtn->setCheckable(true);
QIcon icon;
icon.addFile(":/icons/checked.png", QSize(20, 20), QIcon::Normal, QIcon::On);
icon.addFile(":/icons/unchecked.png", QSize(20, 20), QIcon::Normal, QIcon::Off);
m_batchCheckBtn->setIcon(icon);
m_batchCheckBtn->setIconSize(QSize(28, 28));
m_batchCheckBtn->setStyleSheet("border-style: none;");
connect(m_batchCheckBtn, &QToolButton::clicked, this, &Widget::onBatchCheckClicked);
m_headerView->setHeaderViewWidget(int(MyTableDelegate::DelegateColumnIndex::BatchCheckColumn),
m_batchCheckBtn);
connect(m_headerView, &CustomizeHeaderView::sectionClicked, this, &Widget::onHeaderSectionClicked);
// 设置表头
QStringList horizontaHeaderLables;
horizontaHeaderLables.append("编号");
horizontaHeaderLables.append("");
horizontaHeaderLables.append("文件名");
horizontaHeaderLables.append("修改时间");
horizontaHeaderLables.append("类型");
horizontaHeaderLables.append("大小");
ui->tableWidget->setHorizontalHeaderLabels(horizontaHeaderLables);
}
- 准备数据文件
void Widget::initTableData()
{
QFile file(":/data.txt");
if (!file.open(QFile::ReadOnly)) {
qInfo() << "文件打开失败!";
return;
}
QString line;
QStringList rowList;
while (!file.atEnd()) {
line = file.readLine();
rowList.append(line);
}
initContentsOfTableRow(rowList);
file.close();
}
- 以及表格单元格项点击处理函数、批量选中工具按钮处理还有水平表头section点击处理函数。
void Widget::onTableCellClicked(int row, int column)
{
if (column == int(MyTableDelegate::DelegateColumnIndex::BatchCheckColumn)) {
bool checkState = ui->tableWidget->itemData(row, column).toBool();
ui->tableWidget->setItemData(row, column, !checkState);
}
}
void Widget::onBatchCheckClicked(bool checked)
{
int rowCount = ui->tableWidget->rowCount();
for (int i = 0; i < rowCount; ++i) {
ui->tableWidget->setItemData(i, 1, checked);
}
}
void Widget::onHeaderSectionClicked(int logicalIndex)
{
if (logicalIndex < 2) {
m_headerView->setSortIndicator(currentSortColumn, currentSortOrder);
return;
}
// 返回具有排序指示符的部分的逻辑索引
currentSortColumn = m_headerView->sortIndicatorSection();
// 返回排序指示符的顺序
currentSortOrder = m_headerView->sortIndicatorOrder();
sortTableContents();
}
4 总结
对于QTableWidget类的常用点
- 基本使用(创建其对象并设置行列数、表格单元格相关操作、设置表格头部标题)
- 数据操作(增删改查)
- 样式设置
- 信号与槽(单元格发生变化信号、表格项被双击信号、表格项被点击信号…)