![](/img/trans.png)
[英]Painting the background of a QTableView (with a custom QStyledItemDelegate)
[英]Custom QStyledItemDelegate - Applying Edits to Model
在我的項目中,我將QStyledItemDelegate
子類化,並從createEditor
函數返回了自定義編輯器。
QWidget* TagEditDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
TagEditWidget* tagEditWidget = new TagEditWidget(parent, index.data(Qt::UserRole+4).toInt(), index.data(Qt::UserRole+2).toByteArray(), index.data(Qt::UserRole+3).toByteArray(), index.parent().data(Qt::UserRole+4).toInt() == 9, parent->width());
return tagEditWidget; //tagEditWidget is my custom QWidget
}
編輯完成后,我想將新數據寫回到模型中。 所以我覆蓋了setModelData
。
void TagEditDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
{
TagEditWidget * tagEditWidget = qobject_cast<TagEditWidget*>(editor);
if (!tagEditWidget)
{
QStyledItemDelegate::setModelData(editor, model, index);
return;
}
//Edit model here?
}
這行得通,但是問題是無論關閉編輯器如何,都會調用setModelData
。 我只想在使用EndEditHint
, QAbstractItemDelegate::SubmitModelCache
關閉編輯器的情況下寫入新數據。 所以我將closeEditor
信號連接到我創建的名為editFinished
的插槽。
connect(this, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), this, SLOT(editFinished(QWidget*,QAbstractItemDelegate::EndEditHint)));
現在,我可以看到如何通過EndEditHint
關閉編輯器,以及是否應該將數據寫回到模型中。 在closeEditor
信號之前,Buuuuut, setModelData
得到了調用。 當closeEditor
信號最后被調用時,如何將數據寫回到模型中? 我在這里想念什么嗎?
基本答案:
您的概念似乎很好,直到最后。 我將重點介紹TagEditDelegate::setModelData
方法。
如果您實際上不想更新模型中的數據,只需檢查它是否沒有更改。 意思是當oldData == newData
return;
並跳過模型更新。
補充筆記:
通過查看您的編輯器創建,我得到的印象是它不包含呈現給用戶的單個值。 為了使傳遞參數更友好並且更輕松地比較編輯器數據,請考慮為其創建單獨的class/struct
。 因此,您可以致電:
new TagEditWidget(parent, editorData, parent->width())
其中EditorData是您的類/結構,可以通過單獨的函數獲取:
EditorData editorData = readEditorData(index);
該函數可以在setModelData
方法中重用以檢查條件:
if (tagEditWidget->getEditorData() == readEditorData(index)) return;
還要避免使用像Qt::UserRole+2
這樣的幻數。 創建您自己的枚舉以指定所需的角色。 例如:
enum class MyRole
{
Data1 = Qt::UserRole,
Data2,
Data3,
};
根據評論中的討論進行編輯
如果要發現用戶實際上是否沒有一種方式取消版本,則可以在編輯器或委托中覆蓋eventFilter
。 創建編輯器時,請在構造函數中調用installEventFilter
。 您的eventFilter
實現可能如下所示:
bool eventFilter(QObject *object, QEvent *event) override
{
if (event->type() == QEvent::KeyPress)
{
const auto key = static_cast<QKeyEvent *>(event)->key();
if (key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Tab)
submitted = true;
}
else if (event->type() == QEvent::FocusAboutToChange &&
static_cast<QFocusEvent*>(event)->reason() == Qt::MouseFocusReason)
{
submitted = true;
}
// extetend the conditions (add else if) to include
// events which you might want to treat as submitted
return QLineEdit::eventFilter(object, event);
}
submitted
是在構造函數中初始化為false
的bool
編輯器成員。 然后可以創建一個getter方法isSubmitted()
,並准備檢查setModelData
方法中的狀態。
if (tagEditWidget->isSubmitted())
{
// process data or update model here
}
我只是以自己的方式回答了自己的問題。 我認為,杜斯特的解決方案“更正確”。
我在名為shouldCommit
的委托類中設置了布爾值,並將其設置為false。
然后在setModelData
,檢查是否應將數據寫入模型。
void TagEditDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
{
TagEditWidget * tagEditWidget = qobject_cast<TagEditWidget*>(editor);
if (!tagEditWidget)
{
QStyledItemDelegate::setModelData(editor, model, index);
return;
}
if(shouldCommit)
{
//write data here
}
}
然后,在發出closeEditor
信號時,我檢查了提示並將臨時設置shouldCommit
設置為true, commitData
再次調用commitData
。 現在, shouldCommit
為true,數據被寫入。
void TagEditDelegate::editFinished(QWidget * editor, QAbstractItemDelegate::EndEditHint hint)
{
if(hint == QAbstractItemDelegate::SubmitModelCache)
{
TagEditWidget * tagEditWidget = qobject_cast<TagEditWidget*>(editor);
if(tagEditWidget)
{
shouldCommit = true;
commitData(editor);
shouldCommit = false;
}
}
}
盡管這對我的用例非常有效,但可能並非對所有人都適用,而且Dusteh的注釋部分可能對某些人更有用。 他的方法是重寫eventFilter
並在何時調用commitData
時編寫自己的實現。 對於想要更多控制的人來說,這可能是一個更合適的解決方案。
但是對於任何想要使用默認eventFilter
實現並只看EndEditHint
,這就是我的解決方案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.