相机表格优化
1) 指定单元格“单击即可编辑”
做法(核心思想)
- 整表默认不可编辑;
- 仅对 ScanCode 列(COL_SCAN) 设置可编辑标志 + 自定义委托;
- 捕获
QTableView::clicked
,如果点的是COL_SCAN
,就主动调用edit(idx)
进入编辑器。
对应代码位置
- 初始化表格:整表先关闭编辑(NoEditTriggers),然后只给
COL_SCAN
单元格加Qt::ItemIsEditable
标志GigeAndUsbCameraInfoBurningNew。initTableView()
里:ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers)
;随后在fillTable()
里逐格设置:if (c == COL_SCAN) it->setFlags((it->flags() | Qt::ItemIsEditable) & ~Qt::ItemIsUserCheckable);
GigeAndUsbCameraInfoBurningNew
- 绑定单击即编辑:
connect(ui->tableView, &QTableView::clicked, this, [=](const QModelIndex& idx) { if (!idx.isValid()) return; if (idx.column() == COL_SCAN) { ui->tableView->edit(idx); // 手动开启编辑,仅此一列 } });
代码在
initTableView()
中GigeAndUsbCameraInfoBurningNew COL_SCAN
使用自定义委托ValidatingScanDelegate
,该委托只对指定列创建QLineEdit
编辑器(createEditor
判断列号)GigeAndUsbCameraInfoBurningNewGigeAndUsbCameraInfoBurningNew。
为什么能满足“单击可编辑”
- Qt 默认进入编辑通常需要双击或特定触发器;你把触发器关掉,改为在 clicked 信号中手动调用
edit()
,从而达到单击即编辑的体验GigeAndUsbCameraInfoBurningNew。
可扩展/注意事项
- 如需让其他列也“单击编辑”,在
clicked
槽里增加对应列判断;或把触发逻辑放到自定义委托的editorEvent
中统一管理GigeAndUsbCameraInfoBurningNew。 NoEditTriggers
保证只有你定义的路径能进入编辑,避免误触。
做法(核心思想)
ValidatingScanDelegate
的createEditor()
返回QLineEdit
,并对其绑定:returnPressed
:回车时清理条码枪附带的\r/\n
,commitData
→closeEditor
,并自定义发出scanNextRequested(index)
。textChanged
:兜底,如果扫码直接带了\r/\n
(没按回车),同样提交并触发跳转。
- 主窗体连接
scanNextRequested
:定位到下一行同一列,清空下个单元格并进入编辑。
对应代码位置
- 委托创建编辑器并绑定回车逻辑(节选):
QObject::connect(ed, &QLineEdit::returnPressed, ed, [this, ed, index]() { QString t = ed->text(); while (!t.isEmpty() && (t.endsWith('\n') || t.endsWith('\r'))) t.chop(1); { QSignalBlocker b(ed); ed->setText(t); } emit commitData(ed); emit closeEditor(ed, QAbstractItemDelegate::NoHint); emit scanNextRequested(index); });
同时对
textChanged
做了带回车的兜底提交与跳转GigeAndUsbCameraInfoBurningNew。 - 主窗体里响应跳转:
connect(scanDelegate, &ValidatingScanDelegate::scanNextRequested, this, [=](const QModelIndex& idx) { const int nextRow = idx.row() + 1; if (nextRow >= m_model->rowCount()) return; const QModelIndex nextIdx = m_model->index(nextRow, COL_SCAN); if (!nextIdx.isValid()) return; m_model->setData(nextIdx, QString(), Qt::EditRole); // 自动清空下一行 ui->tableView->setCurrentIndex(nextIdx); ui->tableView->scrollTo(nextIdx, QAbstractItemView::PositionAtCenter); ui->tableView->edit(nextIdx); // 直接进入编辑 });
代码在
initTableView()
中GigeAndUsbCameraInfoBurningNew。 - 另外,委托的
setModelData()
会把解析结果(SN/GUID/MAC/类型/是否OK)写入多种自定义 Role(RoleScanOk/RoleScanSN/...
),并根据合法性把文字颜色置红或清除红色,这保证了边录入边校验GigeAndUsbCameraInfoBurningNew。
为什么能满足“回车/Tab自动跳转”
- 你没有依赖
QAbstractItemView
的默认“导航”,而是在委托里自己定义了“提交→关闭→发跳转信号”的流程,主窗体再把焦点切到下一行COL_SCAN
并启动编辑,形成连贯的录入链路GigeAndUsbCameraInfoBurningNew。 - 如需 Tab 触发,同样可以在
eventFilter
或编辑器里拦截Qt::Key_Tab
,复用同一段提交/跳转逻辑。
可扩展/注意事项
- 条码枪常带回车:你已经对
\r/\n
做了清理和兜底(returnPressed
+textChanged
双路径),非常稳健GigeAndUsbCameraInfoBurningNew。 - 跳转前做校验:你现在通过
validator
与解析函数parseScanLine()
联动,非法则置红+tooltip,合法则写自定义 Role,后续写入前也再次校验GigeAndUsbCameraInfoBurningNew。
做法(核心思想)
- 使用自定义
CheckBoxHeader
作为QTableView
的水平表头; - 表头被点击时,遍历每一行的第一列复选框,统一设置“选中/不选中”;
- 行内复选框变化时,反向统计当前勾选数,把表头状态更新为两态(Checked/Unchecked);
- 第一列单元格配合
CheckToggleDelegate
,实现单击即切换(不用进入编辑器)。
对应代码位置
- 设置表头、宽度和代理:
initTableView()
里创建CheckBoxHeader
并setHorizontalHeader(header)
GigeAndUsbCameraInfoBurningNew;- 第一列 cell 设置
setCheckable(true)
(在fillTable()
)GigeAndUsbCameraInfoBurningNew; COL_CHECK
列绑定CheckToggleDelegate
,在editorEvent
里处理鼠标释放切换Qt::CheckStateRole
GigeAndUsbCameraInfoBurningNew。
- 点击表头 → 全选/全不选:
connect(header, &CheckBoxHeader::checkBoxClicked, ui->tableView, [=](Qt::CheckState state) { m_isClearingChecksProgrammatically = true; Qt::CheckState target = (state == Qt::Checked) ? Qt::Checked : Qt::Unchecked; for (int r = 0; r < m_model->rowCount(); ++r) { auto* item = m_model->item(r, 0); if (item) item->setCheckState(target); } m_isClearingChecksProgrammatically = false; });
GigeAndUsbCameraInfoBurningNew
- 行勾选变化 → 更新表头,两态逻辑(不使用半选):
- 在
initTableView()
和fillTable()
里都对itemChanged
做了统计并header->setCheckState(st)
;你的版本特意把“半选”去掉,只保留 Checked / Unchecked(代码注释里也写了“✅ 仅两态”)GigeAndUsbCameraInfoBurningNew。
- 在
- 防抖/防回环:
- 用
m_isClearingChecksProgrammatically
标记程序批量改勾选的阶段,避免itemChanged
再次触发计算/递归GigeAndUsbCameraInfoBurningNew。
- 用
为什么能满足“表头勾选”
- 复选框不属于默认表头的一部分,必须自绘 + 自定义事件;你通过
CheckBoxHeader
承担“画 + 点击”的工作,通过两条连接完成“表头 → 行”和“行 → 表头”的状态同步,从而实现真正两态的全选/全不选GigeAndUsbCameraInfoBurningNew。 - 行内切换由
CheckToggleDelegate
在鼠标释放时直接翻转CheckStateRole
,手感更快、更直觉GigeAndUsbCameraInfoBurningNew。
可扩展/注意事项
- 若后续需要“全选(仅显示设备)”“全选(仅GEV)”等复杂选择,可把表头改为菜单 + 复选框组合。
- 当前去掉了半选态,更简单;如需恢复半选,在统计勾选数时把“0 < checked < rowCount”映射为
Qt::PartiallyChecked
即可。
- 编辑/勾选时自动暂停“自动刷新”:
- 开始编辑
ScanCode
→scanEditStarted
检测到后autoRefreshCheckBox->setChecked(false)
(触发onStartAuto(Qt::Unchecked)
); - 行内勾选变化、或
itemChanged
触发时,也会关闭自动刷新,避免 UI 被刷新打断当前操作GigeAndUsbCameraInfoBurningNew。 - 自动刷新开/关对应
USBDeviceUpdater/GigeDeviceUpdater
的startAutoRefresh/stopAutoRefresh
调用GigeAndUsbCameraInfoBurningNew。
- 开始编辑
- 录入校验即时反馈:
setModelData()
用parseScanLine()
解析扫码内容并写入多种 Role,再根据ok
与否设置文字变红和 tooltip 提示,这样用户当下就能看到问题GigeAndUsbCameraInfoBurningNew。
- 你把“进入编辑(单击) → 输入(条码枪也稳) → 回车自动跳 → 即时校验提示”串成一条闭环,同时又把“批量选择(表头两态复选)”做成一键操作;并且在用户动手时暂停自动刷新,体验上非常贴近生产线的快速录入/批量写入需求。这三块设计互相咬合,没有互相打架,是一套非常实用的表格交互方案GigeAndUsbCameraInfoBurningNewGigeAndUsbCameraInfoBurningNew。
阅读剩余
版权声明:
作者:傻狍子
链接:https://rowdeer.top/2025/09/07/%e7%9b%b8%e6%9c%ba%e8%a1%a8%e6%a0%bc%e4%bc%98%e5%8c%96/
文章版权归作者所有,未经允许请勿转载。
THE END