1. 问题
使用Qt进行研发时,遇到一个问题,当在系统默认输入法中文(英文输入法或者搜狗就不会触发闪退)的情况下,选中QTableWidget
控件(QTableWidgetItem有焦点,但是不双击), 进行输入,会导致软件错误退出。
这个Bug在Qt的Bug记录里也存在:QTableWidgetItem cause stack overflow
2. 问题复现
输入以下代码,按照问题操作步骤,可复现问题。
ui->tableWidget->setCellWidget(0, 1, new QLineEdit);
3. 解决方案1 设置输入方式,紧急解决方案
ui->tableWidget->setInputMethodHints(Qt::ImhHiddenText);
4. 解决方案2 每个设置Item的地方使用setCellWidget
,非最优解
for (int i = 0; i < ui->tableWidget->rowCount(); ++i){for (int j = 0; j < ui->tableWidget->columnCount(); ++j){ui->tableWidget->setCellWidget(i, j, new QLineEdit);}}
5. 解决方案3 使用代理,首选建议
示例代码
.h
// 自定义代理类,继承自 QStyledItemDelegate
class SpinBoxDelegate : public QStyledItemDelegate
{Q_OBJECT
public:SpinBoxDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}// 创建编辑器,当用户开始编辑单元格时调用QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const override{QSpinBox *editor = new QSpinBox(parent);editor->setMinimum(0);editor->setMaximum(100);return editor;}// 设置编辑器的数据,将模型中的数据设置到编辑器中void setEditorData(QWidget *editor, const QModelIndex &index) const override{int value = index.model()->data(index, Qt::EditRole).toInt();QSpinBox *spinBox = static_cast<QSpinBox*>(editor);spinBox->setValue(value);}// 将编辑器中的数据保存到模型中void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const override{QSpinBox *spinBox = static_cast<QSpinBox*>(editor);int value = spinBox->value();model->setData(index, value, Qt::EditRole);}// 更新编辑器的几何形状,确保编辑器显示在正确位置void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,const QModelIndex &index) const override{editor->setGeometry(option.rect);QStyledItemDelegate::updateEditorGeometry(editor, option, index);}
};
调用:
#include <QtWidgets>int main(int argc, char *argv[])
{QApplication app(argc, argv);// 创建一个表格视图QTableView tableView;// 创建一个标准的表格数据模型QStandardItemModel model(4, 2);model.setHeaderData(0, Qt::Horizontal, "Integer");model.setHeaderData(1, Qt::Horizontal, "Square");// 为表格设置数据模型tableView.setModel(&model);// 创建一个自定义代理实例SpinBoxDelegate delegate;// 将代理应用到第一列tableView.setItemDelegateForColumn(0, &delegate);// 填充表格数据for (int row = 0; row < 4; ++row) {for (int column = 0; column < 2; ++column) {QModelIndex index = model.index(row, column);if (column == 0) {model.setData(index, row);} else {int value = row * row;model.setData(index, value);}}}tableView.show();return app.exec();
}