QTableWidget 是 Qt 提供的一种表格控件(如图 1 所示),类似于我们经常使用的 Excel 表格,可以将数据以表格的方式展示给用户。QTableWidget 的结构布局如图 1 所示。
整个 QTableWidget 表格可以分为 3 个区域:
- 区域 ① 和 ② 都是表头,区域 ① 设置每一行的表头,区域 ② 设置每一列的表头。我们可以自定义两个区域内的表头,比如第一列是各个教程的名称,所以第一列的表头可以修改为“教程名称”;
- 区域 ③ 为数据区,表格中所有的数据都位于此区域,该区域内可以存放单元格,也可以存放按钮、文本框等控件。
默认情况下,表格会显示表头,表头的内容为行号或列号。根据实际需要,我们可以将表头隐藏起来。
QTableWidget 继承自 QTableView 类,QTableView 类也可以用来显示表格控件。QTableWidget 可以看做是 QTableView 的“简易版”或者“升级版”,它们的区别在于:
- QTableWidget 使用起来更简单,而 QTableView 的用法相对比较复杂。
- QTableView 可以存储大量的数据(例如几十万甚至几百万),用户浏览表格中的数据时不会出现卡顿等现象;尽管 QTableWidget 也能用来存储大量的数据,但用户使用时可能出现卡顿等现象,且显示的数据越多,类似的现象越明显。
总之,QTableWidget 只适合显示少量的数据(几百或几千个),如果想要显示更多的数据,应该用 QTableView。此外,QTableView 还有一些更高级的用法,我们会在讲解 QTableView 时做重点介绍。
QTableWidget 框架在实际开发中经常使用,如果您是一名初学者,我建议先学习 QTableWidget 控件,它可以降低您学习 QT 表格控件的成本,可以更快地掌握表格的用法。
QTableWidget表格的创建
使用 QTableWidget 控件,必须先引入<QTableWidget>
头文件。
QTableWidget 类提供了 2 个构造函数,分别是:
QTableWidget(QWidget *parent = Q_NULLPTR)
QTableWidget(int rows, int columns, QWidget *parent = Q_NULLPTR)
第一个构造函数可以在指定的 parent 父窗口中创建一个空的表格,表格中不显示任何单元格(如图 2a) 所示)。第二个构造函数可以在指定的 parent 父窗口中创建一个表格,表格中整齐地排列着 rows 行 columus 列的单元格,每个单元格都是空的(如图 2b) 所示)。
实用 QTableWidget 表格之前,必须指定表格的行和列。我们可以直接调用第 2 个构造函数,这样既创建了表格又指定了行和列。当然,也可以调用第 1 个构造函数先创建表格,然后借助 QTableWidget 类提供的成员方法指定行和列,两种方式都可以。
与数组下标类似,QTableWidget 表格单元格的行标和列标都是从 0 开始。例如在图 2b) 中,选中的单元格的坐标是 (0, 0)。
QTableWidgetItem单元格
QTableWidget 表格中,每个单元格都是 QTableWidgetItem 类的实例对象。
定义 QTableWidgetItem 类的实例对象之前,程序中要引入<QTableWidgetItem>
头文件。QTableWidgetItem 类提供了 4 个构造函数:
QTableWidgetItem(int type = Type)
QTableWidgetItem(const QString &text, int type = Type)
QTableWidgetItem(const QIcon &icon, const QString &text, int type = Type)
QTableWidgetItem(const QTableWidgetItem &other) //复制(拷贝)构造函数
text 参数用于指定单元格要显示的文本(字符串),icon 参数用于指定单元格要显示的图标,type 参数配有默认值,很少用到。
QTableWidgetItem 单元格通常用来存放 text 文本和 icon 图标,借助该类提供的 setBackground()、setTextAlignment() 等成员方法,我们可以轻松设置每个单元格的字体、颜色、背景等。
QTableWidgetItem 类还对<
小于运算符进行了重载,根据各个单元格存储的文本内容(字符串),多个单元格之间可以直接比较大小。借助这一特性,我们可以很轻易地实现“单元格排序”功能。
默认情况下,用户可以选中 QTableWidget 表格中的某个单元格,还可以对目标单元格中的文本内容进行修改。通过设置 QTableWidget 表格,可以禁止用户编辑所有单元格。
QTableWidgetItem 类提供了很多实用的成员方法,其中比较常用的方法如下表所示:
成员方法 | 功 能 |
---|---|
setText(const QString &text) | 设置单元格中的文本。 |
setIcon(const QIcon &icon) | 给单元格添加图标。 |
setBackground(const QBrush &brush) | 设置单元格的背景。 |
setFont(const QFont &font) | 设置单元格中文本的字体。 |
setForeground(const QBrush &brush) | 设置单元格中字体的颜色。 |
setTextAlignment(int alignment) | 设置单元格中文本的对齐方式。 |
setToolTip(const QString &toolTip) | 给单元格设置提示信息。 |
自动调整行高和列宽
QTableWidget 有几个函数自动调整表格的行高和列宽,分别如下:
- resizeColumnsToContents():自动调整所有列的宽度,以适应其内容。
- resizeColumnToContents(int column):自动调整列号为 co/www 的列的宽度。
- resizeRowsToContents():自动调整所有行的高度,以适应其内容。
- resizeRowToContents(int row):自动调整行号为 raw 的行的高度。
设置表格内容是否可编辑
- ui->tableInfo->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);//双击或获取焦点后单击,进入编辑状态
- ui->tableInfo->setEditTriggers(QAbstractItemView::NoEditTriggers); //不允许编辑
设置行表头、列表头是否显示
- ui->tableInfo->horizontalHeader()->setVisible(checked);//是否显示水平表头
- ui->tableInfo->verticalHeader()->setVisible(checked);//是否显示垂直表头
选择模式
- ui->tableInfo->setSelectionBehavior(QAbstractltemView::Selectltems); 单元格选择
- ui->tableInfo->setSelectionBehavior(QAbstractltemView::SelectRows); 行选择
QTableWidget表格的使用
对于创建好的 QTableWidget 表格,我们可以借助该类提供的成员方法快速地操作它。
QTableWidget 类提供了很多实用的成员方法,它还从父类继承了很多方法,下表给大家罗列了实际场景中操作 QTableWidget 表格用得最多的几个方法,这些方法是初学者必须要掌握的:
成员方法 | 功 能 |
---|---|
setRowCount(int rows) | 设置表格的行数。 |
setColumnCount(int columns) | 设置表格的列数。 |
setRowHeight(int row, int height) | 设置指定行的行高。 |
setColumnWidth(int column, int width) | 设置指定列的宽度。 |
setCellWidget(int row, int column, QWidget *widget) | 向表格中的指定位置添加 widget 控件。
|
setHorizontalHeaderLabels(const QStringList &labels) | 设置表格的水平表头。 |
setVerticalHeaderLabels(const QStringList &labels) | 设置表格的竖直表头。 |
setItem(int row, int column, QTableWidgetItem *item) | 向表格指定位置添加单元格。 获取指定位置的单元格,可以借助 item(int row, int column) 或者 itemAt(int ax, int ay) 方法。 |
setEditTriggers(EditTriggers triggers) | 当 triggers 参数值为 QAbstractItemView::NoEditTriggers 时,表示禁止用户编辑单元格。 |
resize(int w, int h) | 设置表格的尺寸。 |
setFont(const QFont &) | 设置表格数据区中文本的字体和大小。 |
QTableWidget信号和槽
QTableWidget 类提供的信号函数,可以监听用户对表格中的哪个单元格进行了何种操作,常见的操作包括点击、双击、按下、编辑等。
下表展示了 QTableWidget 类提供的一些信号函数以及它们各自的功能:
信号函数 | 功 能 |
---|---|
cellClicked(int row,int column) | 当某个单元格被点击时,触发该信号,row 和 columu 就是被点击的单元格的位置。 |
cellDoubleClicked(int row,int column) | 当某个单元格被双击时,触发该信号,row 和 columu 就是被点击的单元格的位置。 |
cellEntered(int row,int column) | 当某个单元格被按下时,触发该信号,row 和 columu 就是被点击的单元格的位置。 |
cellChanged(int row, int column) | 当某个单元格中的数据发生改变时,触发该信号,row 和 columu 就是被改变的单元格的位置。 |
itemClicked(QTableWidgetItem *item) | 当某个单元格被点击时,触发该信号,item 就是被点击的单元格。 |
itemDoubleClicked(QTableWidgetItem *item) | 当某个单元格被双击时,触发该信号,item 就是被双击的单元格。 |
itemEntered(QTableWidgetItem *item) | 当某个单元格被按下时,触发该信号,item 就是被按下的单元格。 |
itemChanged(QTableWidgetItem *item) | 当某个单元格中的数据发生改变时,触发该信号,item 就是被改变的单元格。 |
QTableWiget 表格也可以接收信号并做出相应地响应,例如:
槽函数 | 功 能 |
---|---|
clear() | 删除表格中所有单元格的内容,包括表头。 |
clearContents() | 不删除表头,仅删除表格中数据区内所有单元格的内容, |
insertColumn(int column) | 在表格第 column 列的位置插入一个空列。 |
insertRow(int row) | 在表格第 row 行的位置插入一个空行。 |
removeColumn(int column) | 删除表格中的第 column 列,该列的所有单元格也会一并删除。 |
removeRow(int row) | 删除表格中的第 row 行,该行的所有单元格也会一并删除。 |
scrollToItem(const QTableWidgetItem *item, QAbstractItemView::ScrollHint hint = EnsureVisible) | 滑动到指定的单元格。 |
QTableWidget表格实例
接下来通过一个实例,带大家更深入地了解 QTableWidget 控件的用法。
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QStringList>
#include <QDebug>
#include <QPushButton>
using namespace std;
class QMyLabel:public QLabel{
Q_OBJECT
public slots:
void rsetText(QTableWidgetItem * item);
};
void QMyLabel::rsetText(QTableWidgetItem * item){
this->setText(item->text());
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//创建一个窗口,作为输入框和列表框的父窗口
QWidget widget;
//设置窗口的标题
widget.setWindowTitle("QTableWidget控件");
//自定义窗口的大小
widget.resize(900,500);
//在 widget 窗口中添加一个 4 行 3 列的表格
QTableWidget TableWidget(4,3,&widget);
//自定义表格的尺寸和字体大小
TableWidget.resize(900,350);
TableWidget.setFont(QFont("宋体",20));
//设置表格中每一行的表头
TableWidget.setHorizontalHeaderLabels(QStringList() << "教程" << "网址" << "状态");
//设置表格数据区内的所有单元格都不允许编辑
TableWidget.setEditTriggers(QAbstractItemView::NoEditTriggers);
//设置表格中每一行的内容
TableWidget.setItem(0,0,new QTableWidgetItem("C语言教程"));
TableWidget.setItem(0,1,new QTableWidgetItem("http://c.biancheng.net/c/"));
TableWidget.setItem(0,2,new QTableWidgetItem("已更新完毕"));
TableWidget.setItem(1,0,new QTableWidgetItem("Qt教程"));
TableWidget.setItem(1,1,new QTableWidgetItem("http://c.biancheng.net/qt/"));
TableWidget.setItem(1,2,new QTableWidgetItem("正在更新"));
TableWidget.setItem(2,0,new QTableWidgetItem("C++教程"));
TableWidget.setItem(2,1,new QTableWidgetItem("http://c.biancheng.net/cplus/"));
TableWidget.setItem(2,2,new QTableWidgetItem("已更新完毕"));
//向 widget 窗口中添加一个文本框
QMyLabel lab;
lab.setText("选中单元格");
lab.setParent(&widget);
//自定义文本框的尺寸和位置
lab.resize(900,150);
lab.move(0,350);
lab.setAlignment(Qt::AlignCenter);
lab.setFont(QFont("宋体",16));
widget.show();
//为表格和文本框之间建立关联,当用户点击表格中某个单元格时,文本框显示单元格内的文本内容。
QObject::connect(&TableWidget,&QTableWidget::itemClicked,&lab,&QMyLabel::rsetText);
return a.exec();
}
//QMyLabel类的定义应该放到 .h 文件中,本例中将其写到 main.cpp 中,程序最后需要添加 #include "当前源文件名.moc" 语句,否则无法通过编译。
#include "main.moc"
程序的执行结果为:
实例二:
//设置列数
ui->tableWidget->setColumnCount(4);
//设置行数
ui->tableWidget->setRowCount(5);
//去除选中虚线框
ui->tableWidget->setFocusPolicy(Qt::NoFocus);
//表头标题用QStringList来表示
QStringList headerText;
headerText<<"姓 名"<<"性 别"<<"出生日期"<<"国 籍";
ui->tableWidget->setHorizontalHeaderLabels(headerText);
//设置列宽
ui->tableWidget->setColumnWidth(0,200);
ui->tableWidget->setColumnWidth(1,200);
ui->tableWidget->setColumnWidth(2,200);
ui->tableWidget->setColumnWidth(3,200);
//需要打开右键菜单属性,则必须设置
ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);
//设置最后一栏自适应长度
ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
//设置列内容自适应宽度
//ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
//设置为可以选中多个目标,按ctrl键
ui->tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
//开启交替行背景色,在设置style为交替颜色时必须开启
ui->tableWidget->setAlternatingRowColors(true);
//清除表格数据区的所有内容,但是不清除表头。
// ui->tableWidget->clearContents();
//清除表格数据区的所有内容,包括表头。
// //ui->tableWidget->clear();
2.添加子项
这里添加三个string,和一个自定义的combobox
QComboBox *combox1 = new QComboBox(ui->tableWidget);
combox1->addItem("man");
combox1->addItem("woman");
QComboBox *combox2 = new QComboBox(ui->tableWidget);
combox2->addItem("man");
combox2->addItem("woman");
QComboBox *combox3 = new QComboBox(ui->tableWidget);
combox3->addItem("man");
combox3->addItem("woman");
QComboBox *combox4 = new QComboBox(ui->tableWidget);
combox4->addItem("man");
combox4->addItem("woman");
QComboBox *combox5 = new QComboBox(ui->tableWidget);
combox5->addItem("man");
combox5->addItem("woman");
//添加
ui->tableWidget->setItem(0,0,new QTableWidgetItem("Tom"));
//ui->tableWidget->setItem(0,1,new QTableWidgetItem("man"));
ui->tableWidget->setItem(0,2,new QTableWidgetItem("1999.11.11"));
ui->tableWidget->setItem(0,3,new QTableWidgetItem("England"));
ui->tableWidget->setItem(1,0,new QTableWidgetItem("Jery"));
//ui->tableWidget->setItem(1,1,new QTableWidgetItem("man"));
ui->tableWidget->setItem(1,2,new QTableWidgetItem("1997.08.12"));
ui->tableWidget->setItem(1,3,new QTableWidgetItem("England"));
ui->tableWidget->setItem(2,0,new QTableWidgetItem("Mary"));
//ui->tableWidget->setItem(2,1,new QTableWidgetItem("woman"));
ui->tableWidget->setItem(2,2,new QTableWidgetItem("1998.03.12"));
ui->tableWidget->setItem(2,3,new QTableWidgetItem("England"));
ui->tableWidget->setItem(3,0,new QTableWidgetItem("Jessy"));
//ui->tableWidget->setItem(3,1,new QTableWidgetItem("woman"));
ui->tableWidget->setItem(3,2,new QTableWidgetItem("2000.04.17"));
ui->tableWidget->setItem(3,3,new QTableWidgetItem("England"));
ui->tableWidget->setItem(4,0,new QTableWidgetItem("Jim"));
//ui->tableWidget->setItem(4,1,new QTableWidgetItem("man"));
ui->tableWidget->setItem(4,2,new QTableWidgetItem("1997.09.28"));
ui->tableWidget->setItem(4,3,new QTableWidgetItem("England"));
ui->tableWidget->setCellWidget(0,1,combox1);
ui->tableWidget->setCellWidget(1,1,combox2);
ui->tableWidget->setCellWidget(2,1,combox3);
ui->tableWidget->setCellWidget(3,1,combox4);
ui->tableWidget->setCellWidget(4,1,combox5);
//设置单个item属性
//对单个item进行设置
QTableWidgetItem *item = new QTableWidgetItem("item");
//获取原有字体设置
QFont font = item->font();
//设置为粗体
font.setBold(true);
//字体大小
font.setPointSize(12);
//字体颜色
item->setTextColor(Qt::red);
//设置字体
item->setFont(font);
//文本对齐格式
item->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
3.右键弹出菜单
这里添加一个右键菜单,有两个action,一个删除 一个添加
m_menu = new QMenu(this);
m_actionAdd = new QAction("添加",m_menu);
connect(m_actionAdd,&QAction::triggered,this,&Form::slotAdd);
m_actionDel = new QAction("删除",m_menu);
connect(m_actionDel,&QAction::triggered,this,&Form::slotDel);
m_menu->addAction(m_actionAdd);
m_menu->addAction(m_actionDel);
connect(ui->tableWidget,&QTableWidget::customContextMenuRequested,this,&Form::slotPopMenu);
void Form::slotAdd()
{
int row = ui->tableWidget->currentRow();
ui->tableWidget->insertRow(row);
}
void Form::slotDel()
{
int row = ui->tableWidget->currentRow();
ui->tableWidget->removeRow(row);
}
void Form::slotPopMenu(const QPoint &pos)
{
qDebug()<<pos.x()<<" "<<pos.y();
QPoint p;
p.setX(pos.x());
p.setY(pos.y() + m_menu->height() / 2 );
m_menu->exec(ui->tableWidget->mapToGlobal(p));
}
4.设置风格
这里简单的设置了一下颜色,头部样式,仅供参考。
const QString styles = "QTableView\
{\
selection-background-color: qlineargradient(x1: 0, y1: 0, x2: 0.5, y2: 0.5,\
stop: 0 #616161, stop: 1 505050);\
/*alternate-background-color:blue;*/\
}";
const QString headerStyle = "QHeaderView::section\
{\
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,\
stop:0 #616161, stop: 0.5 #505050,\
stop: 0.6 #434343, stop:1 #656565);\
color: white;\
padding-left: 4px;\
border: 1px solid #6c6c6c;\
}\
/*QHeaderView::section:checked\
{\
background-color: red;\
}*/";
ui->tableWidget->setStyleSheet(styles);
ui->tableWidget->horizontalHeader()->setStyleSheet(headerStyle);
5.清空
clear() 和 removeRow方法都会delete项数据,不必担心内存泄露。
//清除表格数据区的所有内容,但是不清除表头。
ui->tableWidget->clearContents();
//ui->tableWidget->clear();
int nCount = ui->tableWidget->rowCount();
for(int i=0;i<nCount;i++)
{
ui->tableWidget->removeRow(0);
}