我有一个定制的qtablemodel和一个qtableview。我想添加一项功能,用户可以选择多行并通过更改该行中的一个值。他实际上会更改所有行中的这个值。 例如当用户选择整个表格时,可以将表格中所有人员的名字更改为 alice。
你能帮我实现这个目标吗?
我不明白如何为不同的行多次触发模型的 setData 。或者你能告诉我在调用模型中的 setData 函数之前 qtableview 向模型发送哪个信号吗?
提前非常感谢 唐尼
我可能有一个稍微更直接的解决方案来解决同时编辑同一列中所有选定值的问题。与重写 QTableView::edit() 相比,重写 QTableView::commitData(editor) 更容易,该函数在用户提交编辑后调用。
简而言之:当用户提交编辑时,迭代所有其他选定的行,并将完全相同的值更改应用于与编辑的单元格具有相同列的单元格。
这是一个Python示例,翻译成C++应该很容易(到处添加分号,用
self
替换this
):
class ImageTableView(QtGui.QTableView):
def commitData(self, editor):
# call parent commitData first
super(ImageTableView, self).commitData(editor)
# self.currentIndex() is the QModelIndex of the cell just edited
theModel = self.currentIndex().model()
# get the value that the user just submitted
value = theModel.data(self.currentIndex(), QtCore.Qt.EditRole)
curRow, curCol = self.currentIndex().row(), self.currentIndex().column()
# selection is a list of QItemSelectionRange instances
for isr in self.selectionModel().selection():
rows = range(isr.top(), isr.bottom()+1)
for row in rows:
if row != curRow:
# row,curCol is also in the selection. make an index:
idx = theModel.index(row, curCol)
# so we can apply the same value change
theModel.setData(idx, value, QtCore.Qt.EditRole)
你不能从 QTableView::selectedIndexes() 获取 QModelList 并对其进行迭代吗?
QAbstractItemModel::dataChanged
信号连接到循环遍历每个选定项目的插槽。并非每个版本的 setData 都会发出此信号,但如果您覆盖它,您可以选择这样做。
查看 QTableWidgetItem::setData 的源代码作为示例。它位于 qtablewidget.cpp 文件中。
编辑:或者,您可以键入委托的 closeEditor 或 commitData 信号来拦截编辑器的值并将其应用到每个选定的项目。您必须子类化 QTableView 才能完成此任务,因此这里有一些示例代码,可以让您从here:
开始获得灵感class MyTableView : public QTableView {
Q_OBJECT
public:
explicit MyTableView(QWidget* parent = 0) : QTableView(parent) {
connect(this->itemDelegate(), SIGNAL(closeEditor(QWidget*)),
this, SLOT(editMultipleItems(QWidget*)));
}
public slots:
void editMultipleItems(QWidget* editor) {
QLineEdit* myeditor = qobject_cast<QLineEdit*>(editor); //recast to whatever widget was actually used
if(myeditor != 0) {
foreach(const QModelIndex& index, this->selectionModel()->selectedIndexes()) {
QVariant v(myeditor->text());
model()->setData(index, v, Qt::EditRole);
}
}
}
};
作为第三个选项,您可以使用多选的特殊情况覆盖 QStyledItemDelegate,然后自定义 setModelData() 来编辑每个选定的项目,而不仅仅是接收编辑触发器的项目。
您还可以通过让简单子类化的 QStyleItemDelegate::setModelData() 发出一个连接到 MyTableView 的 multiItemEdit 插槽的信号并使用新值来组合第二个和第三个选项。
这是一个自定义 QStyledItemDelegate:
#include "StyledItemDelegateMultipleEdit.h"
StyledItemDelegateMultipleEdit::StyledItemDelegateMultipleEdit(QObject *parent, QItemSelectionModel* itemSelectionModel)
: QStyledItemDelegate(parent)
, itemSelectionModel_(itemSelectionModel)
{}
StyledItemDelegateMultipleEdit::~StyledItemDelegateMultipleEdit()
{}
void StyledItemDelegateMultipleEdit::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
const QModelIndexList& lstIdx = itemSelectionModel_->selectedIndexes();
QStyledItemDelegate::setModelData(editor, model, index);
if (itemSelectionModel_)
{
const QVariant& data = model->data(index);
const QVariant::Type dataType = data.type();
bool bs = model->blockSignals(true);
QModelIndexList lstIdxEdited;
for (const QModelIndex& idx : lstIdx)
{
if(idx != index && idx.data().type()==dataType && ((model->flags(idx) & Qt::ItemIsEditable)==Qt::ItemIsEditable))
{
bool bSuc = model->setData(idx, data);
if (bSuc)
{
lstIdxEdited << idx;
}
}
}
model->blockSignals(bs);
std::sort(lstIdxEdited.begin(), lstIdxEdited.end(), [](const QModelIndex& idx1, const QModelIndex& idx2) {
return idx1.column() < idx2.column() && idx1.row() < idx2.row();
});
emit model->dataChanged(lstIdxEdited.first(), lstIdxEdited.last());
itemSelectionModel_->clearSelection();
}
}