QTableWidget
QTableWidget是用来以表格方式展现数据的结构
QTableWidget的构造函数
cpp
//指定父节点构造QTableWidget
QTableWidget::QTableWidget(QWidget *parent = nullptr)
//指定行号,列号以及父节点构造QTableWidget
QTableWidget::QTableWidget(int rows, int columns, QWidget *parent = nullptr)
示例
cpp
//构造一个三行四列的QTableWidget
auto table_wid = new QTableWidget(3,4);
设置表头
设置行数和列数
cpp
//设置列数
void setColumnCount(int columns);
//获取列数
int columnCount() const;
//设置行数
void setRowCount(int rows);
//返回行数
int rowCount() const;
示例
cpp
auto table_wid = new QTableWidget();
//设置列数为3
table_wid->setColumnCount(3);
//设置行数为3
table_wid->setRowCount(3);
设置水平表头的标签
cpp
void QTableWidget::setHorizontalHeaderLabels(const QStringList &labels)
设置垂直表头的标签信息
cpp
void QTableWidget::setVerticalHeaderLabels(const QStringList &labels)
示例
cpp
auto table_wid = new QTableWidget();
//设置列数为3
table_wid->setColumnCount(3);
//设置行数为3
table_wid->setRowCount(3);
//设置水平标签
table_wid->setHorizontalHeaderLabels(
QStringList()<<"Column 1" << "Column 2" << "Column 3");
//设置垂直标签
table_wid->setVerticalHeaderLabels(
QStringList()<<"Row 1" << "Row 2" << "Row 3");
当前项和选中
当前项
QTableWidget有选中和当前项的概念,
当前项是当前选中的列表项,通过视觉效果显示出来,用户可通过键盘或者鼠标与当前项交互, 比如当前项时第一行第一列

有时会没有当前项,可以通过这个函数判断
cpp
QTableWidgetItem *currentItem() const;
如果这个函数返回值为空,则说明当前QTableWidget没有焦点。
选中
选中和当前项不同,选中可以选择多个,但是当前项只能有一个。
当我们选中一列或一行的时候,当前项所在的单元格可能就变化了。
大家可以看到当我点击第二列的时候,在第二列第一行出现了虚线框,说明当前项变成了第1行第2列。

示例
cpp
//创建3行4列的表格
auto table_wid = new QTableWidget(3,4);
//获取当前item
auto * cur_item = table_wid->currentItem();
设置当前项
我们可以通过setCurrentItem或者setCurrentCell设置当前项
cpp
//设置当前项
void QTableWidget::setCurrentItem(QTableWidgetItem *item)
//设置当前项
void QTableWidget::setCurrentCell(int row, int column)
cpp
//将当前项设置为第1行第1列
ui->tableWidget->setCurrentCell(0,0);
获取当前的列和行
cpp
//返回焦点当前的行
int currentRow() const;
//返回焦点当前的列
int currentColumn() const;
示例
获取当前焦点所在的行号和列号
cpp
//创建3行4列的表格
auto table_wid = new QTableWidget(3,4);
//获取当前行
auto cur_row = table_wid->currentRow();
//获取当前列
auto cur_col = table_wid->currentCol();
插入列
我们可以在指定位置插入一列
cpp
//在第column插入一列
void QTableWidget::insertColumn(int column)
示例
cpp
//创建3行4列的表格
auto table_wid = new QTableWidget(3,3);
//设置水平标签
table_wid->setHorizontalHeaderLabels(
QStringList()<<"Column 1" << "Column 2" << "Column 3");
//设置垂直标签
table_wid->setVerticalHeaderLabels(
QStringList()<<"Row 1" << "Row 2" << "Row 3");
//在第二列处插入一列
table_wid->insertColumn(0);

默认情况下,插入的列名字为其所在的列序号,如果想改为我们自定义的名字可调用
cpp
void setHorizontalHeaderItem(int column, QTableWidgetItem *item);
第一个参数为要修改的头部的哪一列,第二个参数为用item替换这个头部的列
示例
cpp
//创建3行4列的表格
auto table_wid = new QTableWidget(3,3);
//设置水平标签
table_wid->setHorizontalHeaderLabels(
QStringList()<<"Column 1" << "Column 2" << "Column 3");
//设置垂直标签
table_wid->setVerticalHeaderLabels(
QStringList()<<"Row 1" << "Row 2" << "Row 3");
//在第二列处插入一列
table_wid->insertColumn(0);
//更新列的名字
auto * col_item = new QTableWidgetItem("Column 0");
//更新cur_col的列表头
table_wid->setHorizontalHeaderItem(0, col_item);
删除列
cpp
//删除第column列
void removeColumn(int column);
示例
cpp
//删除第2列
table_wid->removeColumn(1);
获取列数
cpp
//返回tablewidget的列数
int columnCount() const;
行的操作和列类似,这里我们列举下行的用法
cpp
//删除行
void removeRow(int row);
//插入行
void insertRow(int row);
//设置垂直表头
QTableWidgetItem *takeVerticalHeaderItem(int row);
更新数据
我们可以更新某一行某一列的单元格内的数据
cpp
//更新row行(从0开始),column列(从0开始)的单元格数据
void setItem(int row, int column, QTableWidgetItem *item);
示例
cpp
//创建一个item用来填充数据
auto new_item = new QTableWidgetItem("hello");
//将item设置到表格中,更新第2行1列数据
table_wid->setItem(1,0,new_item);
删除数据
通过takeItem根据行和列选择要删除的item
cpp
QTableWidgetItem *takeItem(int row, int column);
调用delete删除这个item即可清空单元格数据
cpp
delete item;
点击信号
QTableWidget中的某个item被点击会发出itemClicked信号
cpp
[signal] void QTableWidget::itemClicked(QTableWidgetItem *item)
可以捕获这个信号,对点击的item做一些处理和判断。
注意
QTableWidget中必须有item,点击这个item才会发出itemClicked信号,如果是空的表格是不会发出这个信号的。
对于空表格项或者存储item的表格项,我们可以捕获cellClicked信号
cpp
[signal] void QTableWidget::cellClicked(int row, int column)
示例
cpp
//创建3行4列的表格
auto table_wid = new QTableWidget(3,3);
//连接单元格被点击的信号
connect(table_wid, &QTableWidget::cellClicked, [](int row, int column){
qDebug()<< "row is " << row <<" column is " << column;
})
练习案例
实现如下界面

要求
- 创建一个3行3列的表格,表头列信息分别为Column 1,Column 2,Column 3...
行信息分别为Row1, Row2, Row3...
- 默认为第1行第1列单元格为当前项
- 根据输入的信息,点击增加列,将信息增加到当前列之前。支持在最后一列之后追加列,删除列等操作。
- 根据输入的信息,点击增加行,将信息增加到当前行之前,支持在最后一行之后追加行,删除行等操作。
- 点击选中后,打印当前条目信息。
- 支持更新数据和删除数据操作。
答案
先拖动界面ui布局达到如下效果

界面关系图

接下来我们在MainWindow的构造函数中初始化表格
cpp
//设置列
ui->tableWidget->setColumnCount(3);
//设置行
ui->tableWidget->setRowCount(3);
//设置水平头部标签
ui->tableWidget->setHorizontalHeaderLabels(
QStringList()<<"Column 1" << "Column 2" << "Column 3");
//设置垂直头部标签
ui->tableWidget->setVerticalHeaderLabels(
QStringList()<<"Row 1" << "Row 2" << "Row 3");
//默认设置当前项为第1行第1列
ui->tableWidget->setCurrentCell(0,0);
//初始化焦点信息
qDebug() << ui->tableWidget->currentItem();
auto cur_row = ui->tableWidget->currentRow();
auto cur_col = ui->tableWidget->currentColumn();
qDebug() << cur_row << cur_col;
if(cur_row != -1 && cur_col != -1){
ui->label_4->setText(
QString("当前条目: %1行%2列").arg(cur_row).arg(cur_col));
}
构造函数中,响应某个item被点击,只有在表格中有数据的时候点击才会触发。
cpp
//响应某个item被点击
connect(ui->tableWidget,&QTableWidget::itemClicked,
[this](QTableWidgetItem *item){
ui->label_4->setText( QString("当前条目: %1行%2列").
arg(item->row()).arg(item->column()));
});
响应某个单元格被点击
cpp
//响应某个单元被点击
connect(ui->tableWidget, &QTableWidget::cellClicked,
[this](int row, int column){
ui->label_4->setText( QString("当前条目: %1行%2列").
arg(row).arg(column));
});
响应添加列按钮被点击
cpp
//添加列
connect(ui->addCol,&QPushButton::clicked, [this](){
//判断文本是否为空
if(ui->lineEdit->text().isEmpty()){
QMessageBox::information(this,"通知","输入文本为空");
return;
}
//获取当前单元所在的列
auto cur_col = ui->tableWidget->currentColumn();
if(cur_col < 0){
QMessageBox::information(this,"通知","未选中任何列");
return;
}
//在cur_col位置插入一列
ui->tableWidget->insertColumn(cur_col);
//要插入的文本
auto text = ui->lineEdit->text();
//更新列的名字
auto * col_item = new QTableWidgetItem(text);
//更新cur_col的列表头
ui->tableWidget->setHorizontalHeaderItem(cur_col, col_item);
});
响应追加列被点击
cpp
//追加列
connect(ui->appendCol,&QPushButton::clicked,[this](){
//判断文本是否为空
if(ui->lineEdit->text().isEmpty()){
QMessageBox::information(this,"通知","输入文本为空");
return;
}
//获取列号
auto col_count = ui->tableWidget->columnCount();
//新增一列数据
ui->tableWidget->insertColumn(col_count);
//要插入的文本
auto text = ui->lineEdit->text();
//生成一个item用来更新表头数据
auto col_item = new QTableWidgetItem(text);
//更新表头对应的列数据
ui->tableWidget->setHorizontalHeaderItem(col_count, col_item);
});
响应删除列按钮被点击
cpp
//删除列
connect(ui->delCol,&QPushButton::clicked,[this](){
auto col = ui->tableWidget->currentColumn();
if(col < 0){
QMessageBox::information(this,"通知","未选中任何列");
return;
}
ui->tableWidget->removeColumn(col);
});
响应添加行按钮被点击
cpp
//添加行
connect(ui->addRow,&QPushButton::clicked,[this](){
//判断是否存在当前选中行
auto cur_row = ui->tableWidget->currentRow();
if(cur_row < 0){
QMessageBox::information(this,"通知","未选中任何行");
return;
}
//获取文本输入框内容
auto text = ui->lineEdit->text();
if(text.isEmpty()){
QMessageBox::information(this,"通知","输入信息为空");
return;
}
//在cur_row插入一行
ui->tableWidget->insertRow(cur_row);
//创建一个item用来更新表头的行信息
auto row_item = new QTableWidgetItem(text);
ui->tableWidget->setVerticalHeaderItem(cur_row, row_item);
});
响应删除行和追加行的按钮点击信号
cpp
//删除行
connect(ui->delRow,&QPushButton::clicked,[this](){
//获取当前行
auto cur_row = ui->tableWidget->currentRow();
ui->tableWidget -> removeRow(cur_row);
});
//追加行
connect(ui->appendRow,&QPushButton::clicked,[this](){
//判断文本内容
auto text = ui->lineEdit->text();
if(text.isEmpty()){
QMessageBox::information(this,"通知","输入信息为空");
return;
}
//获取总行数
auto row_count = ui->tableWidget->rowCount();
//在末尾的行后添加一行
ui->tableWidget->insertRow(row_count);
//创建item用来填写表头信息
auto item = new QTableWidgetItem(text);
//把item 放入垂直表头里
ui->tableWidget->setVerticalHeaderItem(row_count,item);
});
添加数据
cpp
//添加数据
connect(ui->addData,&QPushButton::clicked,[this](){
//判断文本内容
auto text = ui->lineEdit->text();
if(text.isEmpty()){
QMessageBox::information(this,"通知","输入信息为空");
return;
}
//获取输入的行号
auto row_str = ui->rowLineEdit->text();
//获取输入的列号
auto col_str = ui->colLineEdit->text();
if(row_str.isEmpty() || col_str.isEmpty()){
QMessageBox::information(this,"通知","行号或列号为空");
return;
}
bool b_success = false;
auto row_int = row_str.toInt(&b_success);
if(!b_success){
QMessageBox::information(this,"通知","行号转换失败");
return;
}
auto col_int = col_str.toInt(&b_success);
if(!b_success){
QMessageBox::information(this,"通知","列号转换失败");
return;
}
//创建一个item用来填充数据
auto new_item = new QTableWidgetItem(text);
//将item设置到表格中
ui->tableWidget->setItem(row_int-1,col_int-1,new_item);
});
响应删除数据的按钮点击事件
cpp
//删除数据
connect(ui->delData, &QPushButton::clicked, [this](){
//判断文本内容
auto text = ui->lineEdit->text();
if(text.isEmpty()){
QMessageBox::information(this,"通知","输入信息为空");
return;
}
//获取输入的行号
auto row_str = ui->rowLineEdit->text();
//获取输入的列号
auto col_str = ui->colLineEdit->text();
if(row_str.isEmpty() || col_str.isEmpty()){
QMessageBox::information(this,"通知","行号或列号为空");
return;
}
bool b_success = false;
auto row_int = row_str.toInt(&b_success);
if(!b_success){
QMessageBox::information(this,"通知","行号转换失败");
return;
}
auto col_int = col_str.toInt(&b_success);
if(!b_success){
QMessageBox::information(this,"通知","列号转换失败");
return;
}
//删除指定行列的数据
auto item = ui->tableWidget->takeItem(row_int-1,col_int-1);
delete item;
});