QTableWidget是表格控件,它以行和列的形式展示和编辑二维表格数据,它的每个单元格都是一个QTableWidgetItem对象
1. 效果演示
本案例展示表格控件的以下操作:
✅ 行表头、列表头的设置
✅ 交替显示背景色
✅ 单元格可编辑
✅ 选择行为:单元格选择或行选择
✅ 数据的增删改查
2. 属性和方法
QTableWidget有很多属性和方法,完整的可查看帮助文档。
2.1 行表头、列表头
表格控件的第一行称为行表头,用于设置每一列的标题
表格控件的第一列称为列表头,用于设置每一行的标题,通常缺省则默认显示行号
2.1.1 设置和获取行列的数目
// 获取/设置行的数目
int rowCount() const
void setRowCount(int rows)
// 获取/设置列的数目
int columnCount() const
void setColumnCount(int columns)
2.1.2 设置行列表头的文本
// 设置行列表头的文本
void setHorizontalHeaderLabels(const QStringList &labels)
void setVerticalHeaderLabels(const QStringList &labels) // 通常不设置,则默认为行号
2.1.3 设置列的宽度
// 首先,获取行表头
QHeaderView *horizontalHeader() const
// 然后,设置列的宽度
void QHeaderView::setSectionResizeMode(QHeaderView::ResizeMode mode)
其中ResizeMode是一个枚举,取值如下:
| 枚举 | 值 | 含义 |
|---|---|---|
| HeaderView::Interactive | 0 | 用户可拖动改变列宽 |
| QHeaderView::Fixed | 2 | 固定列宽 |
| QHeaderView::Stretch | 1 | 拉伸自适应列宽大小 |
| QHeaderView::ResizeToContents | 3 | 根据内容设置列宽 |
通常,先整体设置为QHeaderView::Stretch, 然后根据需要对单独的列进行设置,如下:
// 1. 首先,将所有列都设置为拉伸
ui->twStudent->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); //先自适应宽度
// 2. 然后,单独设置某一列根据内容调整宽度,或者单独设置某一列为固定宽度
// ui->twStudent->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
// ui->twStudent->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
// ui->twStudent->setColumnWidth(0, 80);
2.2 单元格
每个网格单元称为一个单元格。每个单元格有一个行号、列号。
单元格对应的是QTableWidgetItem对象,可以设置其文字内容等。
2.2.1 获取和设置单元格
// 获取和设置指定行列位置的单元格
QTableWidgetItem *item(int row, int column) const;
void setItem(int row, int column, QTableWidgetItem *item)
// 构造 QTableWidgetItem
QTableWidgetItem(const QIcon &icon, const QString &text, int type = Type)
QTableWidgetItem(const QString &text, int type = Type)
2.2.2 单元格文本对齐方式
// 获取和设置单元格文本的对齐方式
int textAlignment() const
void setTextAlignment(int alignment)
其中,Qt::Alignment是一个枚举,常用取值如下:
| 枚举 | 值 | 含义 |
|---|---|---|
| Qt::AlignLeft | 0x0001 | 水平方向-左对齐 |
| Qt::AlignRight | 0x0002 | 水平方向-右对齐 |
| Qt::AlignHCenter | 0x0004 | 水平方向-居中对齐 |
| Qt::AlignTop | 0x0020 | 垂直方向-上对齐 |
| Qt::AlignBottom | 0x0040 | 垂直方向-下对齐 |
| Qt::AlignVCenter | 0x0080 | 垂直方向-居中对齐 |
| Qt::AlignCenter(AlignVCenter | AlignHCenter) | 0x0084 | 垂直方向和水平方向-居中对齐 |
上面的每一个宏,都代表16进制中的一位,可以进行或(|)操作,来同时设置多个对齐方式。
2.2.3 单元格是否可编辑
// 获取和设置单元格是否可编辑
QAbstractItemView::EditTriggers editTriggers() const
void setEditTriggers(QAbstractItemView::EditTriggers triggers)
这是继承自其父类QAbstractItemView中的方法,QAbstractItemView::EditTriggers是一个枚举,常用取值如下:
| 枚举 | 值 | 含义 |
|---|---|---|
| AbstractItemView::NoEditTriggers | 0 | 不可编辑 |
| QAbstractItemView::CurrentChanged | 1 | 当切换单元格时 |
| QAbstractItemView::DoubleClicked | 2 | 当双击单元格时 |
| QAbstractItemView::SelectedClicked | 4 | 当单击一个已选中的单元格时 |
| QAbstractItemView::EditKeyPressed | 8 | 当一个单元格获取焦点,按编辑按键时(F2) |
| QAbstractItemView::AnyKeyPressed | 16 | 当一个单元格获取焦点,按任意键时 |
| QAbstractItemView::AllEditTriggers | 31 | 以上所有条件的组合。(31 = 1 | 2 | 4 | 8 | 16) |
2.3 隔行交替背景色
将奇数行和偶数行,它们的背景色不同,便于用户浏览
// 获取和设置是否允许隔行交替背景色
bool alternatingRowColors() const
void setAlternatingRowColors(bool enable)
2.4 选择模式、选择行为
2.4.1 选择行为
所谓选择行为,是指当点击一个单元格时,是选中该单元格,还是选中一整行
// 获取和设置选择行为
QAbstractItemView::SelectionBehavior selectionBehavior() const
void setSelectionBehavior(QAbstractItemView::SelectionBehavior behavior)
这是继承自其父类QAbstractItemView中的方法,QAbstractItemView::SelectionBehavior是一个枚举,取值为:
| 枚举 | 值 | 含义 |
|---|---|---|
| QAbstractItemView::SelectItems | 0 | 选中单元格 |
| QAbstractItemView::SelectRows | 1 | 选中单元格所在行 |
| QAbstractItemView::SelectColumns | 2 | 选中单元格所在列 |
2.4.2 选择模式
所谓选择模式,是指设置表格控件只可选择单行、可选择多行等。
// 获取和设置选择模式
QAbstractItemView::SelectionMode selectionMode() const
void setSelectionMode(QAbstractItemView::SelectionMode mode)
这是继承自其父类QAbstractItemView中的方法,QAbstractItemView::SelectionMode是一个枚举,取值为:
| 枚举 | 值 | 含义 |
|---|---|---|
| QAbstractItemView::NoSelection | 0 | 不可选择 |
| QAbstractItemView::SingleSelection | 1 | 单行选择,一次只允许选择一行 |
| QAbstractItemView::MultiSelection | 2 | 多行选择,鼠标单击就可以选择多行 |
| QAbstractItemView::ExtendedSelection | 3 | 扩展选择,按shift键选中一个范围内的行,ctrl键可以选中不相邻的行 |
| QAbstractItemView::ContiguousSelection | 4 | 相邻选择,按shift键或ctrl键都可以选中一个范围内的行 |
2.5 增加、删除
// 插入行/删除行
void insertRow(int row);
void removeRow(int row);
2.6 信号槽
// 当用户单击、双击某个单元格时发射。参数是指向被单击单元格的QTableWidgetItem对象的指针。
void itemClicked(QTableWidgetItem *item)
void itemDoubleClicked(QTableWidgetItem *item)
// 当用户单击、双击某个单元格时发射,与itemClicked类似,但使用行号和列号作为参数。
void cellClicked(int row, int column)
void cellDoubleClicked(int row, int column)
3. 从零实现
从零写代码实现整体效果,以演示表格控件的属性以及信号槽的用法
3.1 布局
在UI设计师界面,拖拽对应的控件,修改显示的文字、控件的名称,然后完成布局
- 在右侧的属性窗口中,将
MyWidget窗口的Point Size属性修改为14 - 修改
gridLayout的layoutHorizontalSpacing和layoutVerticalSpacing属性值修改为12,让间隔稍大一些
布局完成效果如下:
3.2 代码实现
3.2.1 初始化行列表头
来到mywidget.cpp的构造函数,修改如下:
MyWidget::MyWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MyWidget) {
ui->setupUi(this);
this->setWindowTitle("明王讲QT | 第二章 常用控件 | 2.13 表格控件QTableWidget");
// 1. 设置行列表头
// 1.1 共有4列,并添加列的名称
ui->tablePerson->setColumnCount(4);
QStringList horizontalHeader;
// clang-format off
horizontalHeader << "姓名" << "性别" << "年龄" << "国籍";
// clang-format on
ui->tablePerson->setHorizontalHeaderLabels(horizontalHeader);
// 1.2 设置列的宽度
// 设置所有列的宽度模式为拉伸
ui->tablePerson->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// 还可以单独设置某一列的宽度模式
// ui->twStudent->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
// 或者,可以单独设置某一列为固定宽度
// ui->twStudent->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
// ui->twStudent->setColumnWidth(0, 80);
}
3.2.2 添加几条数据
首先,在mywidget.h中声明追加行、插入行的成员函数,如下:
class MyWidget : public QWidget {
private:
void appendOneRow(QString name, QString gender, int age, QString province);
void insertOneRow(int row, QString name, QString gender, int age, QString province);
};
然后,在mywidget.cpp中实现这两个函数,如下:
void MyWidget::appendOneRow(QString name, QString gender, int age, QString province) {
// 获取当前行数
int count = ui->tablePerson->rowCount();
qDebug() << "current count:" << count;
// 设置当前行数
ui->tablePerson->setRowCount(count + 1);
QTableWidgetItem* nameItem = new QTableWidgetItem(name);
QTableWidgetItem* genderItem = new QTableWidgetItem(gender);
QTableWidgetItem* ageItem = new QTableWidgetItem(QString::number(age));
QTableWidgetItem* provinceItem = new QTableWidgetItem(province);
nameItem->setTextAlignment(Qt::AlignCenter);
genderItem->setTextAlignment(Qt::AlignCenter);
ageItem->setTextAlignment(Qt::AlignCenter);
provinceItem->setTextAlignment(Qt::AlignCenter);
ui->tablePerson->setItem(count, 0, nameItem);
ui->tablePerson->setItem(count, 1, genderItem);
ui->tablePerson->setItem(count, 2, ageItem);
ui->tablePerson->setItem(count, 3, provinceItem);
}
void MyWidget::insertOneRow(int row, QString name, QString gender, int age, QString province) {
ui->tablePerson->insertRow(row);
// 上面 insertRow 只是插入一个空行,需要手动添加每个单元格的内容
QTableWidgetItem* nameItem = new QTableWidgetItem(name);
QTableWidgetItem* genderItem = new QTableWidgetItem(gender);
QTableWidgetItem* ageItem = new QTableWidgetItem(QString::number(age));
QTableWidgetItem* provinceItem = new QTableWidgetItem(province);
nameItem->setTextAlignment(Qt::AlignCenter);
genderItem->setTextAlignment(Qt::AlignCenter);
ageItem->setTextAlignment(Qt::AlignCenter);
provinceItem->setTextAlignment(Qt::AlignCenter);
ui->tablePerson->setItem(row, 0, nameItem);
ui->tablePerson->setItem(row, 1, genderItem);
ui->tablePerson->setItem(row, 2, ageItem);
ui->tablePerson->setItem(row, 3, provinceItem);
}
最后,在mywidget.cpp的构造函数中,调用以上两个函数初始化添加几条数据,如下:
MyWidget::MyWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MyWidget) {
// 2. 添加几行初始化数据
appendOneRow("李雷", "男", 12, "中国");
appendOneRow("韩梅梅", "女", 11, "中国");
appendOneRow("林涛", "男", 13, "中国");
appendOneRow("Lily", "女", 13, "美国");
appendOneRow("Lucy", "女", 13, "美国");
insertOneRow(1, "Tom", "男", 12, "加拿大");
}
3.2.3 复选按钮槽函数
首先,在mywidget.h中声明4个槽函数,如下:
class MyWidget : public QWidget {
private slots:
void on_chkHHeader_checkStateChanged(Qt::CheckState state);
void on_chkVHeader_checkStateChanged(Qt::CheckState state);
void on_chkAlternating_checkStateChanged(Qt::CheckState state);
void on_chkCellEditable_checkStateChanged(Qt::CheckState state);
};
然后,在mywidget.cpp中实现这4个函数,如下:
void MyWidget::on_chkHHeader_checkStateChanged(Qt::CheckState state) {
if ( state == Qt::Checked ) {
ui->tablePerson->horizontalHeader()->show();
} else if ( state == Qt::Unchecked ) {
ui->tablePerson->horizontalHeader()->hide();
}
}
void MyWidget::on_chkVHeader_checkStateChanged(Qt::CheckState state) {
if ( state == Qt::Checked ) {
ui->tablePerson->verticalHeader()->show();
} else if ( state == Qt::Unchecked ) {
ui->tablePerson->verticalHeader()->hide();
}
}
void MyWidget::on_chkAlternating_checkStateChanged(Qt::CheckState state) {
if ( state == Qt::Checked ) {
ui->tablePerson->setAlternatingRowColors(true);
} else if ( state == Qt::Unchecked ) {
ui->tablePerson->setAlternatingRowColors(false);
}
}
void MyWidget::on_chkCellEditable_checkStateChanged(Qt::CheckState state) {
if ( state == Qt::Checked ) {
// 当双击单元格/选中单元格然后单击/按下编辑键F2,都可以编辑单元格。
ui->tablePerson->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed);
} else if ( state == Qt::Unchecked ) {
ui->tablePerson->setEditTriggers(QAbstractItemView::NoEditTriggers);
}
}
最后,在mywidget.cpp的构造中设置复选框的默认状态
MyWidget::MyWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MyWidget) {
// 3. 设置复选框的默认状态
ui->chkVHeader->click(); // 默认显示列列表头
ui->chkHHeader->click(); // 默认显示行表头
ui->chkAlternating->click(); // 交替显示行的背景色;
ui->chkCellEditable->click(); // 默认让单元格可编辑;
}
3.2.4 行选择、单元格选择
首先,在mywidget.h中声明槽函数,如下:
#include <QButtonGroup>
class MyWidget : public QWidget {
private slots:
void onBtnGroupClicked(int id);
private:
QButtonGroup *btnGroup;
};
然后,在mywidget.cpp中实现这个槽函数,如下:
void MyWidget::onBtnGroupClicked(int id) {
if ( id == 0 ) {
ui->tablePerson->setSelectionMode(QAbstractItemView::SingleSelection);
ui->tablePerson->setSelectionBehavior(QAbstractItemView::SelectItems);
} else if ( id == 1 ) {
ui->tablePerson->setSelectionMode(QAbstractItemView::SingleSelection);
ui->tablePerson->setSelectionBehavior(QAbstractItemView::SelectRows);
}
}
最后,在mywidget.cpp的构造函数中,关联信号槽,并将两个单选按钮放到一个组内,如下:
MyWidget::MyWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MyWidget) {
// 4. 设置行选择还是单元格选择
btnGroup = new QButtonGroup(this);
btnGroup->addButton(ui->radioCellSelect, 0);
btnGroup->addButton(ui->radioRowSelect, 1);
connect(btnGroup, &QButtonGroup::idClicked, this, &MyWidget::onBtnGroupClicked);
ui->radioCellSelect->click();
}
3.2.5 增删改查
首先,在mywidget.h中声明槽函数,如下:
class MyWidget : public QWidget {
private slots:
void on_tablePerson_itemClicked(QTableWidgetItem* item); // 条目点击
void on_btnAdd_clicked(); // 追加
void on_btnInsert_clicked(); // 插入
void on_btnDelete_clicked(); // 删除
void on_btnModify_clicked(); // 修改
};
然后,在mywidget.cpp中实现这几个槽函数,如下:
void MyWidget::on_tablePerson_itemClicked(QTableWidgetItem* item) {
int row = item->row();
QString name = ui->tablePerson->item(row, 0)->text();
QString gender = ui->tablePerson->item(row, 1)->text();
QString age = ui->tablePerson->item(row, 2)->text();
QString province = ui->tablePerson->item(row, 3)->text();
ui->lineEditName->setText(name);
ui->lineEditGender->setText(gender);
ui->lineEditAge->setText(age);
ui->lineEditCountry->setText(province);
}
void MyWidget::on_btnAdd_clicked() {
QString name = ui->lineEditName->text();
QString gender = ui->lineEditGender->text();
int age = ui->lineEditAge->text().toInt();
QString province = ui->lineEditCountry->text();
appendOneRow(name, gender, age, province);
}
void MyWidget::on_btnInsert_clicked() {
QString name = ui->lineEditName->text();
QString gender = ui->lineEditGender->text();
int age = ui->lineEditAge->text().toInt();
QString province = ui->lineEditCountry->text();
// 获取当前选中的行号
int currentRow = ui->tablePerson->currentRow();
insertOneRow(currentRow, name, gender, age, province);
}
void MyWidget::on_btnDelete_clicked() {
// 获取当前选中的行号
int currentRow = ui->tablePerson->currentRow();
ui->tablePerson->removeRow(currentRow);
}
void MyWidget::on_btnModify_clicked() {
QString name = ui->lineEditName->text();
QString gender = ui->lineEditGender->text();
int age = ui->lineEditAge->text().toInt();
QString province = ui->lineEditCountry->text();
// 获取当前选中的行号
int currentRow = ui->tablePerson->currentRow();
QTableWidgetItem* nameItem = new QTableWidgetItem(name);
QTableWidgetItem* genderItem = new QTableWidgetItem(gender);
QTableWidgetItem* ageItem = new QTableWidgetItem(QString::number(age));
QTableWidgetItem* provinceItem = new QTableWidgetItem(province);
nameItem->setTextAlignment(Qt::AlignCenter);
genderItem->setTextAlignment(Qt::AlignCenter);
ageItem->setTextAlignment(Qt::AlignCenter);
provinceItem->setTextAlignment(Qt::AlignCenter);
ui->tablePerson->setItem(currentRow, 0, nameItem);
ui->tablePerson->setItem(currentRow, 1, genderItem);
ui->tablePerson->setItem(currentRow, 2, ageItem);
ui->tablePerson->setItem(currentRow, 3, provinceItem);
}
4. 点赞、获取源码
看到这里的小伙伴,去B站给明王一个【免费的点赞】吧,你的支持,是我持续更新优质内容的动力,感谢~
源码下载地址
链接: https://pan.baidu.com/s/1-Bb-VFhb5208LLkoZtrTMQ
提取码: ming







