一个表格的进化史(五)
上一篇我们使用setCellWidget来帮助我们在表格中进行编辑操作,当有很多行都需要同样的操作时这种方法就感觉有点繁琐了。特别是当需要使用信号/槽时。不过幸运的是Qt给我们提供了更高大上的办法:delegate(委托,也有翻译为代理的)。那么我们该如何操作呢?
1.首先从Item代理类中派生一个自己的类。如:
class MyTableItemDelegate : public QStyledItemDelegate
然后重写createEditor函数:
if(index.column() == 3) { QComboBox* cbx = new QComboBox(parent); cbx->addItem(QStringLiteral("男")); cbx->addItem(QStringLiteral("女")); return cbx; }else{ return QStyledItemDelegate::createEditor(parent,option,index); }
判断当前如果是第4列(下标为3)时,创建一个下拉框并添加两个Item然后返回,其他列使用默认方法处理。最后让表格使用这个代理:
ui->tableWidget->setItemDelegate(new MyTableItemDelegate);
我们看到了和使用setCellWidget一样的效果,只不过用这样的方式更简洁一点。我们不仅可以给表格设置代理,还可以为指定行或列设置代理。
void setItemDelegateForColumn(int column, QAbstractItemDelegate *delegate) //为列设置代理 void setItemDelegateForRow(int row, QAbstractItemDelegate *delegate //为行设置代理
如果上面使用ui->tableWidget->setItemDelegateForColumn(3,new MyTableItemDelegate)。那么在createEditor函数中就不需要判断当前列了。
故事到这里还没有结束,如果我们使用图片替换下拉框中的文字时就会发现一个问题:
if(index.column() == 3) { QComboBox* cbx = new QComboBox(parent); cbx->addItem(QIcon("f:/05_test/tx.jpg"),""); //只显示图片 cbx->addItem(QIcon("f:/05_test/tx2.jpg"),""); return cbx; }else{ return QStyledItemDelegate::createEditor(parent,option,index); }
通过下拉框选择后表格中的内容为空。其实同时还存在另一个问题,那就是当设置了表格中的内容后下拉框中的内容不会跟着改。换句话说就是单元格和创建的编辑器内容不同步。
当遇到这样的情况时,我们还需要重写两个函数,手动将两边的数据对应起来即:
//virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;//设置模型的数据 //virtual void setEditorData(QWidget *editor, const QModelIndex &index) const; //设置编辑器的数据 void MyTableItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { if(index.column() == 3){ QComboBox* cbx = qobject_cast<QComboBox*>(editor); if(cbx->currentIndex() == 0){ model->setData(index,QStringLiteral("男")); }else{ model->setData(index,QStringLiteral("女")); } } } void MyTableItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if(index.column() == 3){ QComboBox* cbx = qobject_cast<QComboBox*>(editor); QString str = index.model()->data(index).toString(); if(str == QStringLiteral("男")){ cbx->setCurrentIndex(0); }else{ cbx->setCurrentIndex(1); } } }