如何捕获QTableWidgetItem编辑时按下ESC键的中止操作?
解决QTableWidget捕获ESC中止编辑的问题
这个问题我之前也碰到过!QTableWidget的编辑控件(比如QLineEdit这类)是临时创建的独立子组件,事件会直接发给编辑器本身,不会传递给父级的QTableWidget,所以直接给table装事件过滤器肯定抓不到ESC按键。给你两个实用的解决方案,按需选择:
方案一:监听closeEditor信号(推荐,无需子类化)
QTableWidget的closeEditor信号会在编辑器关闭时触发,其中的EndEditHint参数可以直接告诉你编辑结束的原因——RevertModelCache就是用户按下ESC中止编辑的标识。这个方法最简单,不用修改原有控件结构:
// 在你的窗口类构造函数或者初始化代码里 connect(ui->tableWidget, &QTableWidget::closeEditor, this, [=](QWidget *editor, QAbstractItemDelegate::EndEditHint hint) { if (hint == QAbstractItemDelegate::RevertModelCache) { // 这里处理ESC中止编辑的逻辑 qDebug() << "用户按下ESC,编辑已中止"; // 比如可以获取当前编辑的单元格索引: QModelIndex currentIndex = ui->tableWidget->currentIndex(); qDebug() << "中止编辑的单元格:行" << currentIndex.row() << "列" << currentIndex.column(); } });
方案二:子类化QTableWidget,给编辑器安装事件过滤器
如果你需要在用户按下ESC的瞬间就做出响应(而不是等编辑器关闭后),可以通过重写createEditor方法,给每个新建的编辑器安装事件过滤器,这样就能直接捕获编辑器的按键事件:
// 先自定义一个继承自QTableWidget的类 class MyTableWidget : public QTableWidget { Q_OBJECT public: explicit MyTableWidget(QWidget *parent = nullptr) : QTableWidget(parent) {} protected: // 重写创建编辑器的方法,给每个编辑器装事件过滤器 QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override { QWidget *editor = QTableWidget::createEditor(parent, option, index); // 给编辑器安装当前table作为事件过滤器(因为createEditor是const方法,需要const_cast转换) editor->installEventFilter(const_cast<MyTableWidget*>(this)); return editor; } // 实现事件过滤器 bool eventFilter(QObject *obj, QEvent *event) override { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); if (keyEvent->key() == Qt::Key_Escape) { // 捕获到ESC按键,发送自定义信号通知外部 emit editCancelled(currentIndex()); // 别忘了调用父类的事件过滤器,保证编辑器的正常行为不受影响 return QTableWidget::eventFilter(obj, event); } } return QTableWidget::eventFilter(obj, event); } signals: // 自定义信号,传递中止编辑的单元格索引 void editCancelled(const QModelIndex &index); };
然后在你的窗口里使用这个自定义的MyTableWidget,连接它的editCancelled信号即可:
connect(ui->myTableWidget, &MyTableWidget::editCancelled, this, [=](const QModelIndex &index) { qDebug() << "单元格" << index.row() << "," << index.column() << "的编辑被ESC中止"; });
补充说明
为什么直接给QTableWidget装事件过滤器没用?因为编辑状态下的控件是Qt委托(Delegate)临时创建的独立子控件,它的事件会被自己优先处理,不会向上传递给QTableWidget,所以必须直接给编辑器本身安装事件过滤器,或者利用Qt提供的closeEditor信号来判断编辑结束的原因。
内容的提问来源于stack exchange,提问作者Tobias Leupold
相关产品推荐
相关产品推荐

