【发布时间】:2014-11-28 01:02:15
【问题描述】:
我有一个包含简单和复杂数据的模型,我希望使用就地小部件来编辑简单数据,但使用模式对话框来编辑复杂数据......我怎样才能以一种简洁的方式实现这一点? (我真的更喜欢通过 QItemDelegate 的子类来做所有事情,而不是查看特定的 hack)
【问题讨论】:
标签: c++ qt model-view-controller delegates
我有一个包含简单和复杂数据的模型,我希望使用就地小部件来编辑简单数据,但使用模式对话框来编辑复杂数据......我怎样才能以一种简洁的方式实现这一点? (我真的更喜欢通过 QItemDelegate 的子类来做所有事情,而不是查看特定的 hack)
【问题讨论】:
标签: c++ qt model-view-controller delegates
我认为您必须对视图进行子类化并覆盖 QAbstractItemView::edit() 函数来处理不同的编辑路径。例如:
class MyView : public QTreeView
{
[..]
protected:
bool edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
{
if (index.row() > 5) { // Use your own criteria for simple/complex data
// Simple data with default editor.
return QTreeView::edit(index, trigger, event);
} else {
// Edit complex data.
QDialog dialog;
dialog.exec();
return false;
}
}
[..]
};
【讨论】:
MyView。委托的问题是您必须提供一个将在您的视图中显示的小部件,但它不能是模式对话框。
edit() 成员函数,请注意 Qt 通常会在 edit() 中执行的一些检查需要手动完成。特别是,需要检查编辑触发器和索引标志,以确保仅当所选项目可编辑并且仅根据您配置的触发器(例如双击)时才显示编辑器对话框。为此,只需检查editTriggers() & trigger 和index.flags() & (Qt::ItemIsEditable | Qt::ItemIsUserCheckable) 是否为真。
尝试下一个委托。我在示例中展示了主要思想:
标题:
#ifndef ITEMDELEGATE_H
#define ITEMDELEGATE_H
#include <QItemDelegate>
class ItemDelegate : public QItemDelegate
{
Q_OBJECT
public:
explicit ItemDelegate(QObject *parent = 0);
protected:
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void setEditorData(QWidget * editor, const QModelIndex & index) const;
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const;
void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index) const;
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
signals:
public slots:
};
#endif // ITEMDELEGATE_H
我只向您展示editorEvent,因为您可以自己编写所有其他方法,它将是自定义委托,但在editorEvent 我们创建模态对话框。
bool ItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
const QStyleOptionViewItem &option,
const QModelIndex &index)
{
if(index.row()%2)//specific items, you can use it another options, it is just example
{
QInputDialog* dia = new QInputDialog;//create dialog, just example, it can be your QDialog subclass
dia->setInputMode(QInputDialog::TextInput);
//dia->setAttribute(Qt::WA_DeleteOnClose);
dia->setModal(true);
connect(dia, &QInputDialog::finished,[=]()//connection which will take data from dialog
{
model->setData(index,dia->textValue());//provide some method in your dialog to get user data and set it in model
delete dia;//we don't want memory leaks
});
dia->show();
}
return QItemDelegate::editorEvent(event,model,option,index);
}
我在这里使用了C++11(CONFIG += c++11 到.pro 文件)和new syntax of signals and slots
【讨论】:
if 中添加一个return true;(它是导致错误的return false),并使用QPointer 来存储直径。然后它应该工作。 (还需要添加一个测试来检查它是否是引起事件的双击,但这是特定于用户的)......但是正如您所经历的那样,这个解决方案非常危险,但它似乎是唯一可以解决问题的方法
这是一个老问题,但鉴于这两个答案都不令人满意(返回 false 时崩溃、嵌套事件循环等)... 请注意,我并没有责怪海报上说“不能这样干净地完成”。
完全不同的受支持方法怎么样?
我之前有一个这样的实现(伪代码):
.
auto item = model->item(row, column);
item->setFlags(item->flags() & ~Qt::ItemFlag::ItemIsEditable); // not editable
QAbstractItemView::activated
忽略“简单”项目的事件
connect(m_ui.tableView,
&QAbstractItemView::activated,
this,
&QtGuiApplication2::onDataActivated);
//...
void QtGuiApplication2::onDataActivated(const QModelIndex &index) {
if(!is_complex)
return;
EditDialog dlg;
if(dlg.exec() == QDialog::DialogCode::Accepted) {
updatemodel();
}
}
物品委托: 忽略“复杂”项目。
QWidget* VariableEditorDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
if(is_complex)
return nullptr; // same as base class
return new EditorWidget(parent);
}
现在这当然不如只有代理那么好,但至少它不会在崩溃时如此紧密地避开。
【讨论】: