[Qt] 点击QTableWidget item项后键盘输入导致崩溃

复现场景

Qt版本 5.9.8

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
   
   
    ui->setupUi(this);

    ui->tableWidget->setRowCount(1);
    ui->tableWidget->setColumnCount(2);

    QLineEdit *lineEdit = new QLineEdit(this);
    ui->tableWidget->setCellWidget(0, 1, lineEdit);
}

Widget::~Widget()
{
   
   
    delete ui;
}

选中第一个item,在中文输入法下随便点击一个字母键,程序崩溃,在debug模式下显示的是函数调用栈溢出。如图
在这里插入图片描述

解决方案

这个bug实际上也有人提交到了Qt官方收集bug的地方 QTableWidgetItem cause stack overflow。但是好像没有引起关注 🤣。所有推荐 将原本使用 setCellWidget 的地方使用代理来实现效果 或者 QtableWidget的每一个项都使用 setCellWidget。

使用代理来解决问题

为了能够一直显示控件,而不是用户双击后才显示控件。我们使用

void QAbstractItemView::openPersistentEditor(const QModelIndex &index)

MyStyledItemDelegate.cpp

#include "MyStyledItemDelegate.h"

MyStyledItemDelegate::MyStyledItemDelegate(QObject 
<think>好的,我需要帮助用户在QTQTableWidget中获取点击QTableWidgetItem左下顶点的坐标。首先,我应该回顾一下QTableWidget的相关知识,特别是如何获取的位置和坐标。 用户提到点击QTableWidgetItem时获取其左下顶点的坐标。我知道QTableWidgetItem本身并不直接存储位置信息,位置信息由QTableWidget管理。要获取的位置,可能需要通过QTableWidget的visualRect方法或使用的行列索引来计算坐标。 首先,当用户点击一个item时,可以通过itemClicked信号连接到槽函数。在槽函数中,获取被点击item的行和列,即row和column。然后,需要找到该item在widget中的坐标位置。 QTableWidget的visualRect方法可以返回item的矩形区域,即QRect对象。这个矩形的左上角坐标可以通过rect.topLeft()获取,而左下角则是左上角的x坐标加上rect的height,得到y坐标。不过,可能更直接的方式是使用rect.bottomLeft(),这样可以直接得到左下角的坐标点。不过需要注意坐标系的方向,在QT中,y轴向下增长,所以底部y值更大。 接下来,要将这个相对于QTableWidget的坐标转换为全局坐标或者父组件的坐标。可以使用QTableWidget的viewport()函数获取视口,然后使用mapToGlobal或mapToParent方法进行坐标转换。例如,获取到item的rect后,调用mapToGlobal(rect.bottomLeft())得到全局坐标,或者根据需要使用其他转换方法。 另外,需要考虑表格中的滚动情况。如果表格有滚动条,visualRect会自动考虑当前的滚动位置,因此使用visualRect是正确的选择,因为它返回的是视口中的可见区域的位置,而逻辑上的位置可能需要其他方法。 现在,我需要验证这些步骤是否正确。查阅QT文档,QTableWidget的visualRect方法确实需要行和列作为参数,返回QRect。然后,通过rect的bottomLeft()方法获取左下角的坐标点,再通过mapToGlobal转换坐标。这一步是正确的。 此外,处理点击事件时,要确保正确连接到槽函数,并在槽函数中获取当前选中的item。例如,使用currentItem()方法或者在itemClicked信号的槽函数参数中获取item。 可能的代码结构如下: 在自定义的QTableWidget子类或窗口类中,连接itemClicked信号到槽函数: connect(tableWidget, &QTableWidget::itemClicked, this, &MyClass::onItemClicked); 槽函数实现: void MyClass::onItemClicked(QTableWidgetItem *item) { int row = item->row(); int col = item->column(); QRect rect = tableWidget->visualRect(item->index()); QPoint bottomLeft = rect.bottomLeft(); QPoint globalPos = tableWidget->viewport()->mapToGlobal(bottomLeft); // 使用globalPos或者其他需要的坐标 } 需要注意的是,如果item被部分隐藏或滚动,visualRect仍然返回正确的视口坐标。此外,如果item的显示区域被调整过样式,比如有边距,可能需要进一步调整坐标,但通常visualRect已经包含了这些因素。 可能的错误点:没有正确获取视口(viewport)的坐标转换,或者错误地使用了逻辑位置而非视觉位置。确保使用viewport()->mapToGlobal来转换坐标,因为item的矩形是相对于视口的。 总结步骤: 1. 连接itemClicked信号到槽函数。 2. 在槽函数中获取item的行列。 3. 使用visualRect获取item的矩形。 4. 提取左下角坐标。 5. 转换为全局或父组件坐标。</think>要在QT中获取点击的$QTableWidgetItem$左下顶点的坐标,可以按照以下步骤实现: ### 实现步骤 1. **连接信号与槽**:绑定$QTableWidget$的`itemClicked(QTableWidgetItem*)`信号到自定义槽函数。 2. **获取行列索引**:通过`item->row()`和`item->column()`获取点击的行列。 3. **计算视觉矩形**:调用`visualRect(item->index())`获取在视口中的显示区域$QRect$。 4. **提取左下坐标**:使用`rect.bottomLeft()`获取左下顶点相对视口的坐标。 5. **坐标转换**:通过`viewport()->mapToGlobal()`转换为全局坐标,或`mapToParent()`转换为父组件坐标。 ### 示例代码 ```cpp // 槽函数实现 void MyClass::onItemClicked(QTableWidgetItem *item) { if (!item) return; // 获取行列 int row = item->row(); int column = item->column(); // 获取在视口中的矩形区域 QRect rect = ui->tableWidget->visualRect(item->index()); // 计算左下顶点坐标(相对视口) QPoint bottomLeft = rect.bottomLeft(); // 转换为全局坐标 QPoint globalPos = ui->tableWidget->viewport()->mapToGlobal(bottomLeft); qDebug() << "左下顶点全局坐标:" << globalPos; } ``` ### 关键说明 - **坐标系注意**:QT中界面坐标系原点在左上角,$y$轴向下递增,因此`bottomLeft()`的$y$值比左上角大[^1]。 - **滚动区域处理**:`visualRect()`已自动考虑滚动偏移,无需额外计算[^3]。 - **样式影响**:若自定义了单元格边距或样式,需通过`QStyle`相关方法调整坐标计算[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值