Qt 技巧笔记(十四):QTableWidget 表格组件
<h1 id="qt-技巧笔记十四qtablewidget-表格组件">Qt 技巧笔记(十四):QTableWidget 表格组件</h1><p> Qt 是一个跨平台C++图形界面平台,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍<code>TableWidget</code>表格组件的常用方法及灵活运用。其核心特点:</p>
<ul>
<li>内置数据存储模型(<code>QTableWidgetItem</code>)</li>
<li>支持单元格级别的编辑和选择</li>
<li>提供行列表头、单元格式的高度自定义能力</li>
<li>包含丰富的信号槽机制,便于交互响应</li>
</ul>
<p>其<code>QTableWidget</code>类层次结构:</p>
<pre><code class="language-makefile">QObject
└── QWidget
└── QFrame
└── QAbstractScrollArea
└── QAbstractItemView
└── QTableView
└── QTableWidget
</code></pre>
<p><code>QTableWidget</code> 继承自<code> QTableView</code> 类,<code>QTableView </code>类也可以用来显示表格控件。<code>QTableWidget</code> 可以看做是 <code>QTableView</code> 的“简易版”或者“升级版”,它们的区别在于:</p>
<ul>
<li><code>QTableWidget</code> 使用起来更简单,而 <code>QTableView</code> 的用法相对比较复杂。</li>
<li><code>QTableView</code> 可以存储大量的数据(例如几十万甚至几百万),用户浏览表格中的数据时不会出现卡顿等现象;尽管 <code>QTableWidget</code> 也能用来存储大量的数据,但用户使用时可能出现卡顿等现象,且显示的数据越多,类似的现象越明显。</li>
</ul>
<p>总之,QTableWidget 只适合显示少量的数据(几百或几千个),如果想要显示更多的数据,应该用 <code>QTableView</code>。此外,<code>QTableView</code> 还有一些更高级的用法,我们会在讲解 <code>QTableView</code> 时做重点介绍。</p>
<h2 id="11-qtablewidget-的基本api接口汇总">1.1 QTableWidget 的基本API接口汇总</h2>
<p> <code>QTableWidget</code>是<code>Qt</code>中用于显示表格数据的部件。它是<code>QTableView</code>的子类,提供了一个简单的接口,适用于一些不需要使用自定义数据模型的简单表格场景。<code>QTableWidget</code>提供了一个方便的接口来创建和操作表格中的数据。<code>QTableWidget</code>该组件可以看作是<code>TreeWidget</code>树形组件的高级版本,表格组件相较于树形结构组件灵活性更高,不仅提供了输出展示二维表格功能,还可以直接对表格元素直接进行编辑和修改操作,表格结构分为表头、表中数据两部分,表格结构可看作一个二维数组,通过数组行列即确定特定元素。 以下是<code>QTableWidget</code>类的一些常用方法API的简要说明:</p>
<p>表 1 QTableWidget类常用成员方法</p>
<table>
<thead>
<tr>
<th style="text-align: left">方法</th>
<th style="text-align: left">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><code>setItem(int row, int column, QTableWidgetItem *item)</code></td>
<td style="text-align: left">设置指定行和列的项</td>
</tr>
<tr>
<td style="text-align: left"><code>item(int row, int column) const</code></td>
<td style="text-align: left">返回指定行和列的项</td>
</tr>
<tr>
<td style="text-align: left"><code>setRowCount(int rows)</code></td>
<td style="text-align: left">设置表格的行数</td>
</tr>
<tr>
<td style="text-align: left"><code>setColumnCount(int columns)</code></td>
<td style="text-align: left">设置表格的列数</td>
</tr>
<tr>
<td style="text-align: left"><code>rowCount() const</code></td>
<td style="text-align: left">返回表格的行数</td>
</tr>
<tr>
<td style="text-align: left"><code>columnCount() const</code></td>
<td style="text-align: left">返回表格的列数</td>
</tr>
<tr>
<td style="text-align: left"><code>setHorizontalHeaderLabels(const QStringList &labels)</code></td>
<td style="text-align: left">设置水平表头的标签</td>
</tr>
<tr>
<td style="text-align: left"><code>setVerticalHeaderLabels(const QStringList &labels)</code></td>
<td style="text-align: left">设置垂直表头的标签</td>
</tr>
<tr>
<td style="text-align: left"><code>setItemPrototype(QTableWidgetItem *item)</code></td>
<td style="text-align: left">设置原型项,用于在新插入的单元格中创建副本</td>
</tr>
<tr>
<td style="text-align: left"><code>insertRow(int row)</code></td>
<td style="text-align: left">在指定行插入新行</td>
</tr>
<tr>
<td style="text-align: left"><code>removeRow(int row)</code></td>
<td style="text-align: left">移除指定行</td>
</tr>
<tr>
<td style="text-align: left"><code>insertColumn(int column)</code></td>
<td style="text-align: left">在指定列插入新列</td>
</tr>
<tr>
<td style="text-align: left"><code>removeColumn(int column)</code></td>
<td style="text-align: left">移除指定列</td>
</tr>
<tr>
<td style="text-align: left"><code>clear()</code></td>
<td style="text-align: left">清空表格的所有内容</td>
</tr>
<tr>
<td style="text-align: left"><code>clearContents()</code></td>
<td style="text-align: left">清空表格的所有单元格的内容,但保留表头和行列数</td>
</tr>
<tr>
<td style="text-align: left"><code>itemAt(int x, int y) const</code></td>
<td style="text-align: left">返回给定坐标下的项</td>
</tr>
<tr>
<td style="text-align: left"><code>setCurrentItem(QTableWidgetItem *item)</code></td>
<td style="text-align: left">设置当前项,用于指定当前被选择的项</td>
</tr>
<tr>
<td style="text-align: left"><code>currentItem() const</code></td>
<td style="text-align: left">返回当前被选择的项</td>
</tr>
<tr>
<td style="text-align: left"><code>setCurrentCell(int row, int column)</code></td>
<td style="text-align: left">设置当前单元格,用于指定当前被选择的单元格</td>
</tr>
<tr>
<td style="text-align: left"><code>currentRow() const</code></td>
<td style="text-align: left">返回当前被选择的行号</td>
</tr>
<tr>
<td style="text-align: left"><code>currentColumn() const</code></td>
<td style="text-align: left">返回当前被选择的列号</td>
</tr>
<tr>
<td style="text-align: left"><code>setItemDelegate(QAbstractItemDelegate *delegate)</code></td>
<td style="text-align: left">设置项代理,用于自定义单元格的显示和编辑方式</td>
</tr>
<tr>
<td style="text-align: left"><code>setSortingEnabled(bool enable)</code></td>
<td style="text-align: left">启用或禁用排序功能</td>
</tr>
<tr>
<td style="text-align: left"><code>sortItems(int column, Qt::SortOrder order)</code></td>
<td style="text-align: left">对指定列进行排序</td>
</tr>
<tr>
<td style="text-align: left"><code>setEditTriggers(EditTriggers triggers)</code></td>
<td style="text-align: left">设置触发编辑的事件</td>
</tr>
<tr>
<td style="text-align: left"><code>editItem(QTableWidgetItem *item)</code></td>
<td style="text-align: left">编辑指定项的内容</td>
</tr>
<tr>
<td style="text-align: left"><code>openPersistentEditor(QTableWidgetItem *item)</code></td>
<td style="text-align: left">打开指定项的持久编辑器</td>
</tr>
<tr>
<td style="text-align: left"><code>closePersistentEditor(QTableWidgetItem *item)</code></td>
<td style="text-align: left">关闭指定项的持久编辑器</td>
</tr>
<tr>
<td style="text-align: left"><code>itemChanged(QTableWidgetItem *item)</code></td>
<td style="text-align: left">当项的内容发生变化时发出的信号</td>
</tr>
<tr>
<td style="text-align: left"><code>cellClicked(int row, int column)</code></td>
<td style="text-align: left">单元格被单击时发出的信号</td>
</tr>
<tr>
<td style="text-align: left"><code>cellDoubleClicked(int row, int column)</code></td>
<td style="text-align: left">单元格被双击时发出的信号</td>
</tr>
</tbody>
</table>
<p>这些方法提供了对 <code>QTableWidget</code> 的基本操作和配置的途径。使用这些方法,你可以动态地调整表格的大小、内容,设置表头,进行排序,处理编辑触发事件等。在.pro项目文件中添加必要的模块:</p>
<pre><code class="language-makefile">QT += core gui widgets
</code></pre>
<p>下表展示了<code>QTableWidget</code>类提供的一些信号函数以及它们各种的,其常用的信号总结如下:</p>
<p>表 2 QTableWidget信号函数汇总</p>
<table>
<thead>
<tr>
<th style="text-align: center">信号</th>
<th style="text-align: center">触发条件与功能</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><code>cellClicked(int row,int column)</code></td>
<td style="text-align: center">当某个单元格被点击时,触发该信号,<code>row</code> 和 <code>columu</code> 就是被点击的单元格的位置。</td>
</tr>
<tr>
<td style="text-align: center"><code>cellDoubleClicked(int row,int column)</code></td>
<td style="text-align: center">当某个单元格被双击时,触发该信号,<code>row</code> 和 <code>columu</code> 就是被点击的单元格的位置。</td>
</tr>
<tr>
<td style="text-align: center"><code>cellEntered(int row,int column)</code></td>
<td style="text-align: center">当某个单元格被按下时,触发该信号,<code>row</code> 和 <code>columu</code> 就是被点击的单元格的位置。</td>
</tr>
<tr>
<td style="text-align: center"><code>cellChanged(int row, int column)</code></td>
<td style="text-align: center">当某个单元格中的数据发生改变时,触发该信号,<code>row</code> 和 <code>columu</code> 就是被改变的单元格的位置。</td>
</tr>
<tr>
<td style="text-align: center"><code>itemClicked(QTableWidgetItem *item)</code></td>
<td style="text-align: center">当某个单元格被点击时,触发该信号,<code>item</code> 就是被点击的单元格。</td>
</tr>
<tr>
<td style="text-align: center"><code>itemDoubleClicked(QTableWidgetItem *item)</code></td>
<td style="text-align: center">当某个单元格被双击时,触发该信号,<code>item</code> 就是被双击的单元格。</td>
</tr>
<tr>
<td style="text-align: center"><code>itemEntered(QTableWidgetItem *item)</code></td>
<td style="text-align: center">当某个单元格被按下时,触发该信号,<code>item</code> 就是被按下的单元格。</td>
</tr>
<tr>
<td style="text-align: center"><code>itemChanged(QTableWidgetItem *item)</code></td>
<td style="text-align: center">当某个单元格中的数据发生改变时,触发该信号,<code>item</code> 就是被改变的单元格。</td>
</tr>
<tr>
<td style="text-align: center"><code>activated(QModelIndex)</code></td>
<td style="text-align: center">当用户激活<code>index</code>指定的项目时,发出信号</td>
</tr>
<tr>
<td style="text-align: center"><code>cellActivated(int row,int column)</code></td>
<td style="text-align: center">单元格被激活时,发出信号,并传递(行,列)</td>
</tr>
</tbody>
</table>
<p>QTableWidget 表格也可以接收信号并做出相应地响应,例如:</p>
<p>表 3 QTableWidget常用槽函数</p>
<table>
<thead>
<tr>
<th style="text-align: center">槽函数</th>
<th style="text-align: center">功 能</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><code>clear()</code></td>
<td style="text-align: center">删除表格中所有单元格的内容,包括表头。</td>
</tr>
<tr>
<td style="text-align: center"><code>clearContents()</code></td>
<td style="text-align: center">不删除表头,仅删除表格中数据区内所有单元格的内容。</td>
</tr>
<tr>
<td style="text-align: center"><code>insertColumn(int column)</code></td>
<td style="text-align: center">在表格第 column 列的位置插入一个空列</td>
</tr>
<tr>
<td style="text-align: center"><code>insertRow(int row)</code></td>
<td style="text-align: center">在表格第 row 行的位置插入一个空行。</td>
</tr>
<tr>
<td style="text-align: center"><code>removeColumn(int column)</code></td>
<td style="text-align: center">删除表格中的第 column 列,该列的所有单元格也会一并删除。</td>
</tr>
<tr>
<td style="text-align: center"><code>removeRow(int row)</code></td>
<td style="text-align: center">删除表格中的第 row 行,该行的所有单元格也会一并删除。</td>
</tr>
<tr>
<td style="text-align: center"><code>scrollToItem(const QTableWidgetItem *item, QAbstractItemView::ScrollHint hint = EnsureVisible)</code></td>
<td style="text-align: center">滑动到指定的单元格。</td>
</tr>
</tbody>
</table>
<p>其信号的中信号槽连接使用 <code>QObject::connect</code>,通常采用函数指针语法(<code>Qt5/6</code> 推荐)或宏 <code>SIGNAL/SLOT</code></p>
<table>
<thead>
<tr>
<th style="text-align: left">信号</th>
<th style="text-align: left">连接示例</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><code>cellClicked(int row, int column)</code></td>
<td style="text-align: left"><code>connect(table, &QTableWidget::cellClicked, this, &MyClass::onCellClicked);</code></td>
</tr>
<tr>
<td style="text-align: left"><code>cellDoubleClicked(int row, int column)</code></td>
<td style="text-align: left"><code>connect(table, &QTableWidget::cellDoubleClicked, ...);</code></td>
</tr>
<tr>
<td style="text-align: left"><code>cellChanged(int row, int column)</code></td>
<td style="text-align: left"><code>connect(table, &QTableWidget::cellChanged, ...);</code></td>
</tr>
<tr>
<td style="text-align: left"><code>currentCellChanged(int currentRow, int currentCol, int previousRow, int previousCol)</code></td>
<td style="text-align: left"><code>connect(table, &QTableWidget::currentCellChanged, ...);</code></td>
</tr>
<tr>
<td style="text-align: left"><code>itemClicked(QTableWidgetItem *item)</code></td>
<td style="text-align: left"><code>connect(table, &QTableWidget::itemClicked, ...);</code></td>
</tr>
<tr>
<td style="text-align: left"><code>itemChanged(QTableWidgetItem *item)</code></td>
<td style="text-align: left"><code>connect(table, &QTableWidget::itemChanged, ...)</code></td>
</tr>
</tbody>
</table>
<p>示例:</p>
<pre><code class="language-C++">// 头文件声明槽函数
private slots:
void onCellClicked(int row, int column);
// 连接
connect(ui->tableWidget, &QTableWidget::cellClicked, this, &MyWidget::onCellClicked);
// 实现
void MyWidget::onCellClicked(int row, int column)
{
qDebug() << "Clicked cell" << row << column;
}
</code></pre>
<h2 id="12-创建qtablewidget的表格">1.2 创建QTableWidget的表格</h2>
<p>创建表格涉及到的成员函数有:</p>
<pre><code class="language-C++">// 构造函数
QTableWidget::QTableWidget(QWidget *parent = nullptr)
QTableWidget::QTableWidget(int rows, int columns, QWidget *parent = nullptr)
// 设置行数
void QTableWidget::setRowCount(int rows);
// 设置列数
void QTableWidget::setColumnCount(int columns)
</code></pre>
<p>创建<code>QTableWidget</code> 的基本方式一般有两种:</p>
<pre><code class="language-C++">// 方式1:在代码中直接创建
QTableWidget *tableWidget = new QTableWidget(this);
tableWidget->setRowCount(20); // 设置20行
tableWidget->setColumnCount(10); // 设置10列
// 方式2:在UI设计器中拖放添加
// 在Qt Designer中拖放"Table Widget"到窗体
// 然后在代码中通过ui指针访问
ui->tableWidget->setRowCount(20);
ui->tableWidget->setColumnCount(10);
</code></pre>
<h2 id="13-qtablewidget常用设置表格属性">1.3 QTableWidget常用设置表格属性</h2>
<p> 我们需要总结常用的设置表格属性的API,包括行列、表头、选择模式、编辑触发、尺寸调整、样式等。可以按功能分类,给出API名称和简要说明。最好也提及对应的枚举值。</p>
<h3 id="131-表头设置">1.3.1 表头设置</h3>
<table>
<thead>
<tr>
<th style="text-align: left">方法</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><code>setHorizontalHeaderLabels(list)</code></td>
<td style="text-align: left">设置水平表头文字</td>
</tr>
<tr>
<td style="text-align: left"><code>setVerticalHeaderLabels(list)</code></td>
<td style="text-align: left">设置垂直表头文字</td>
</tr>
<tr>
<td style="text-align: left"><code>horizontalHeader().setVisible(bool)</code></td>
<td style="text-align: left">显示/隐藏水平表头</td>
</tr>
<tr>
<td style="text-align: left"><code>verticalHeader().setVisible(bool)</code></td>
<td style="text-align: left">显示/隐藏垂直表头</td>
</tr>
</tbody>
</table>
<h3 id="132-选择行为与模式">1.3.2 选择行为与模式</h3>
<table>
<thead>
<tr>
<th style="text-align: left">方法 / 枚举</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><code>setSelectionBehavior(QTableWidget.SelectionBehavior)</code></td>
<td style="text-align: left">选择行为: <code>SelectItems</code>(单元格,默认) <code>SelectRows</code>(整行) <code>SelectColumns</code>(整列)</td>
</tr>
<tr>
<td style="text-align: left"><code>setSelectionMode(QTableWidget.SelectionMode)</code></td>
<td style="text-align: left">选择模式: <code>NoSelection</code>(禁止选择) <code>SingleSelection</code>(单选) <code>MultiSelection</code>(多选) <code>ExtendedSelection</code>(扩展选择,支持 <code>Ctrl/Shift</code>) <code>ContiguousSelection</code>(连续多选)</td>
</tr>
</tbody>
</table>
<h3 id="133-行列尺寸调整">1.3.3 行列尺寸调整</h3>
<table>
<thead>
<tr>
<th style="text-align: left">方法</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><code>resizeColumnsToContents()</code></td>
<td style="text-align: left">所有列宽适应内容</td>
</tr>
<tr>
<td style="text-align: left"><code>resizeRowsToContents()</code></td>
<td style="text-align: left">所有行高适应内容</td>
</tr>
<tr>
<td style="text-align: left"><code>setColumnWidth(int col, int width)</code></td>
<td style="text-align: left">设置指定列宽(像素)</td>
</tr>
<tr>
<td style="text-align: left"><code>setRowHeight(int row, int height)</code></td>
<td style="text-align: left">设置指定行高(像素)</td>
</tr>
<tr>
<td style="text-align: left"><code>horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode)</code></td>
<td style="text-align: left">设置列宽调整模式: <code>Interactive</code>(用户可调,默认) <code>Fixed</code>(固定) <code>Stretch</code>(拉伸填满剩余空间) <code>ResizeToContents</code>(根据内容自动调整)</td>
</tr>
<tr>
<td style="text-align: left"><code>verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode)</code></td>
<td style="text-align: left">同上,用于行高调整</td>
</tr>
</tbody>
</table>
<h3 id="134-外观样式">1.3.4 外观样式</h3>
<table>
<thead>
<tr>
<th style="text-align: left">方法</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><code>void setAlternatingRowColors(bool enable)</code></td>
<td style="text-align: left">是否交替行颜色</td>
</tr>
<tr>
<td style="text-align: left"><code>void setShowGrid(bool show)</code></td>
<td style="text-align: left">是否显示网格线</td>
</tr>
<tr>
<td style="text-align: left"><code>void setGridStyle(Qt::PenStyle style)</code></td>
<td style="text-align: left">网格线样式:<code>Qt::SolidLine</code>, <code>Qt::DashLine</code>, <code>Qt::DotLine</code> 等</td>
</tr>
<tr>
<td style="text-align: left"><code>void setCornerButtonEnabled(bool enable)</code></td>
<td style="text-align: left">左上角全选按钮是否可见</td>
</tr>
</tbody>
</table>
<h3 id="135-其他常用设置">1.3.5 其他常用设置</h3>
<table>
<thead>
<tr>
<th style="text-align: left">方法</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><code>void setSortingEnabled(bool enable)</code></td>
<td style="text-align: left">是否启用点击表头排序</td>
</tr>
<tr>
<td style="text-align: left"><code>void setWordWrap(bool on)</code></td>
<td style="text-align: left">单元格文本是否自动换行</td>
</tr>
<tr>
<td style="text-align: left"><code>void setTextElideMode(Qt::TextElideMode mode)</code></td>
<td style="text-align: left">文本过长省略模式:<code>Qt::ElideLeft</code>, <code>ElideRight</code>, <code>ElideMiddle</code>, <code>ElideNone</code></td>
</tr>
</tbody>
</table>
<h2 id="14-qtablewidget-示-例">1.4 QTableWidget 示 例</h2>
<p>QTableWidget提供了<code>cellDoubleClicked</code>信号,当用户双击单元格时触发该信号。通过连接该信号到自定义槽函数,可以获取被双击单元格的行列索引和内容。</p>
<pre><code class="language-C++">#include <QApplication>
#include <QTableWidget>
#include <QMessageBox>
#include <QHeaderView>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 创建表格控件
QTableWidget tableWidget(5, 3); // 5行3列
tableWidget.setWindowTitle("QTableWidget双击示例");
// 设置表头
QStringList headers;
headers << "姓名" << "年龄" << "职业";
tableWidget.setHorizontalHeaderLabels(headers);
// 填充示例数据
QStringList names = {"张三", "李四", "王五", "赵六", "钱七"};
QStringList jobs = {"工程师", "医生", "教师", "律师", "设计师"};
for(int row = 0; row < 5; ++row) {
tableWidget.setItem(row, 0, new QTableWidgetItem(names));
tableWidget.setItem(row, 1, new QTableWidgetItem(QString::number(20 + row)));
tableWidget.setItem(row, 2, new QTableWidgetItem(jobs));
}
// 连接双击信号
QObject::connect(&tableWidget, &QTableWidget::cellDoubleClicked, [&](int row, int column){
QTableWidgetItem *item = tableWidget.item(row, column);
QString message = QString("行: %1\n列: %2\n内容: %3")
.arg(row + 1)
.arg(column + 1)
.arg(item ? item->text() : "空");
QMessageBox::information(&tableWidget, "单元格内容", message);
});
// 调整列宽
tableWidget.horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
tableWidget.show();
return app.exec();
}
</code></pre>
<h3 id="关键技术点说明">关键技术点说明</h3>
<ol>
<li><strong>信号连接</strong>:使用<code>QObject::connect</code>将<code>cellDoubleClicked</code>信号连接到<code>lambda</code>表达式</li>
<li><strong>行列索引</strong>:信号参数直接提供被双击单元格的行列索引(从0开始)</li>
<li><strong>内容获取</strong>:通过<code>item(row, column)</code>方法获取<code>QTableWidgetItem</code>对象</li>
<li><strong>空值处理</strong>:检查item指针是否为<code>nullptr</code>,避免空指针异常</li>
<li><strong>界面反馈</strong>:使用<code>QMessageBox</code>显示获取到的单元格信息</li>
</ol><br><br>
来源:https://www.cnblogs.com/GeophysicsWorker/p/19794662
頁:
[1]