前言:

学习qt表格控制,写博文记录:

【QT表格-1】QStandardItem的堆内存释放需要单独delete,还是随QStandardItemModel的remove或clear自动销毁?

【QT表格-2】QTableWidget单元格结束编辑操作endEditting_qtablewidget 单元格编辑事件

【QT表格-3】QTableWidget导入/导出excel通用代码,不需要安装office,不依赖任何多余环境,甚至不依赖编程语言

【QT表格-4】由QTableView/QTableWidget显示进度条和按钮,理解qt代理delegate用法

【QT表格-5】QTableView用代码设置选中状态

【QT表格-6】QTableWidget的currentCellChanged实现中途撤销

背景:

qt提供了QTableView和QTableWidget,使用view和model方式相对简单很多,可以直接把实时修改数据更新到数据库并支持事务。我曾想利用好它简化编程,但事实上我没有用这种方式,而是使用了widget+item方式。因为我需要更灵活的界面交互和数据库交互。所以我自己按照以前的思路包装了一个grid控件类。

qt默认的方式,编辑单元格后,移动焦点结束编辑状态,编辑的内容才更新到单元格。这一点我很不爽。我希望编辑框和单元格的关系对用户是透明的。比如我重写的按键事件,如果用户按下ctrl+s就对外发送保存信号执行保存操作,如果按下方向键可以移动焦点,按下del可以删除,按下insert可以插入。

但是执行保存时,如果焦点不移开,编辑的内容更新不到单元格,是无法保存成功的。所以上网看大家怎么说。见到很多人提到希望有endEditting这样的函数,还有说使用setEnabled、editTrigger等。我都觉得不够好。就像大家说的,搞不好还要及时屏蔽信号的发出,以免触发不必要的响应。

而setEnabled和editTrigger这种还需要考虑原有的状态,动作太大。而我做的表格允许模板定义是否可编辑,所以不希望动用这些函数。

方法:

我认为,既然移动焦点能更新到单元格,那就执行一次移动焦点即可。但主子表切换数据显示我用到了currentRowChanged信号,所以要避免焦点在行之间变动。于是就让焦点在本行中移动到列-1,再移动回来即可。相当于实现了endEditting。

//'Ctrl+s' to send the saving signal.
    if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_S)
    {
        //Change the current cell to end the editting.
        //Do it in the same row and it won't trigger the currentRowChanged slot.
        int iCurRow = this->currentRow();
        int iCurCol = this->currentColumn();
        this->setCurrentCell(iCurRow, -1);
        this->setCurrentCell(iCurRow, iCurCol);
        emit sigSave();
    }

至少我个人认为,还是比较合适的。

以为这样就结束了吗?事实上我想错了,上面的办法有漏洞。行列的值,qt认为-1是非法的,所以当列号置为-1时,行号也会成为-1。因此,上面的写法还是会触发cellchanged槽函数的行变动。最后我重实现了一个rowchanged信号,配合标记解决问题。

有些时候,保存操作执行完毕后我会重新加载数据,为了提高用户感受,可以提前记住当前单元格的位置,重新加载后要再定位到这里。但不能只使用行列的索引,因为尤其对于行,有可能重新被排序,所以我写的表格类中重载了setCurrentCell函数,允许通过主键定位。

傻事:

曾为了处理keyPress事件,居然自己写了逻辑,后来发现qt默认的方式就挺好,于是直接调用继承方法解决。

QTableWidget::keyPressEvent(event);

该休息就休息,不换脑子容易短路。