QLineEdit如何触发QAbstractItemDelegate::commitData
How does QLineEdit triger QAbstractItemDelegate::commitData
我正在使用 QTreeView
和 QAbstractItemModel
开发 Qt 应用程序。
该模型包含一些异构数据,需要不同的控件进行编辑。我通过自定义委托来实现它,查询 model.data(Qt::EditRole)
并且模型将 return QWidget
用作编辑器。
我喜欢 QLineEdit
的工作方式 - 当我按下回车键时,delegate::setModelData
会自动调用,所以我 不需要 连接 QLineEdit::editingFinished
到 QAbstractItemDelegate::setModelData()
,这非常方便,因为 QLineEdit 是从模型 returned 作为 QWidget
到委托的,它不必关心它是什么类型的小部件.
使用 QComboBox
有点棘手 - 我希望组合框在做出选择后提交,到目前为止我只能通过 connect(myComboBox, SIGNAL(activated(QString)), myDelegate, commitData()));
来完成
但是,我的代表不知道编辑器小部件的类型,我不想为模型最终传递给它的每个新编辑器编辑代表的代码。当在连接到其 activated()
信号的插槽中单击输入时,我真的很想强制组合框执行与 QLineEdit 相同的操作。
那么,QLineEdit
调用委托的 setModelData
做什么?
Qt 中是否有一种通用的编辑方式,无论它是什么 "I'm done editing, take the data and pass it to the model"?
QStyledItemDelegate
(和 QItemDelegate
)定义了一个事件过滤器,如果您按 Tab 键或 return。
,它会调用 commitData
请参阅 Qt 4.8.6 source 中的以下摘录:
bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event)
{
QWidget *editor = qobject_cast<QWidget*>(object);
if (!editor)
return false;
if (event->type() == QEvent::KeyPress) {
switch (static_cast<QKeyEvent *>(event)->key()) {
case Qt::Key_Tab:
emit commitData(editor);
emit closeEditor(editor, QAbstractItemDelegate::EditNextItem);
return true;
case Qt::Key_Backtab:
emit commitData(editor);
emit closeEditor(editor, QAbstractItemDelegate::EditPreviousItem);
return true;
case Qt::Key_Enter:
case Qt::Key_Return:
#ifndef QT_NO_TEXTEDIT
if (qobject_cast<QTextEdit *>(editor) || qobject_cast<QPlainTextEdit *>(editor))
return false; // don't filter enter key events for QTextEdit
// We want the editor to be able to process the key press
// before committing the data (e.g. so it can do
// validation/fixup of the input).
#endif // QT_NO_TEXTEDIT
#ifndef QT_NO_LINEEDIT
if (QLineEdit *e = qobject_cast<QLineEdit*>(editor))
if (!e->hasAcceptableInput())
return false;
#endif // QT_NO_LINEEDIT
QMetaObject::invokeMethod(this, "_q_commitDataAndCloseEditor",
Qt::QueuedConnection, Q_ARG(QWidget*, editor));
return false;
case Qt::Key_Escape:
// don't commit data
emit closeEditor(editor, QAbstractItemDelegate::RevertModelCache);
break;
default:
return false;
}
if (editor->parentWidget())
editor->parentWidget()->setFocus();
return true;
} else if (event->type() == QEvent::FocusOut || (event->type() == QEvent::Hide && editor->isWindow())) {
//the Hide event will take care of he editors that are in fact complete dialogs
if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) {
QWidget *w = QApplication::focusWidget();
while (w) { // don't worry about focus changes internally in the editor
if (w == editor)
return false;
w = w->parentWidget();
}
#ifndef QT_NO_DRAGANDDROP
// The window may lose focus during an drag operation.
// i.e when dragging involves the taskbar on Windows.
if (QDragManager::self() && QDragManager::self()->object != 0)
return false;
#endif
emit commitData(editor);
emit closeEditor(editor, NoHint);
}
} else if (event->type() == QEvent::ShortcutOverride) {
if (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Escape) {
event->accept();
return true;
}
}
return false;
}
我正在使用 QTreeView
和 QAbstractItemModel
开发 Qt 应用程序。
该模型包含一些异构数据,需要不同的控件进行编辑。我通过自定义委托来实现它,查询 model.data(Qt::EditRole)
并且模型将 return QWidget
用作编辑器。
我喜欢 QLineEdit
的工作方式 - 当我按下回车键时,delegate::setModelData
会自动调用,所以我 不需要 连接 QLineEdit::editingFinished
到 QAbstractItemDelegate::setModelData()
,这非常方便,因为 QLineEdit 是从模型 returned 作为 QWidget
到委托的,它不必关心它是什么类型的小部件.
使用 QComboBox
有点棘手 - 我希望组合框在做出选择后提交,到目前为止我只能通过 connect(myComboBox, SIGNAL(activated(QString)), myDelegate, commitData()));
来完成
但是,我的代表不知道编辑器小部件的类型,我不想为模型最终传递给它的每个新编辑器编辑代表的代码。当在连接到其 activated()
信号的插槽中单击输入时,我真的很想强制组合框执行与 QLineEdit 相同的操作。
那么,QLineEdit
调用委托的 setModelData
做什么?
Qt 中是否有一种通用的编辑方式,无论它是什么 "I'm done editing, take the data and pass it to the model"?
QStyledItemDelegate
(和 QItemDelegate
)定义了一个事件过滤器,如果您按 Tab 键或 return。
commitData
请参阅 Qt 4.8.6 source 中的以下摘录:
bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event)
{
QWidget *editor = qobject_cast<QWidget*>(object);
if (!editor)
return false;
if (event->type() == QEvent::KeyPress) {
switch (static_cast<QKeyEvent *>(event)->key()) {
case Qt::Key_Tab:
emit commitData(editor);
emit closeEditor(editor, QAbstractItemDelegate::EditNextItem);
return true;
case Qt::Key_Backtab:
emit commitData(editor);
emit closeEditor(editor, QAbstractItemDelegate::EditPreviousItem);
return true;
case Qt::Key_Enter:
case Qt::Key_Return:
#ifndef QT_NO_TEXTEDIT
if (qobject_cast<QTextEdit *>(editor) || qobject_cast<QPlainTextEdit *>(editor))
return false; // don't filter enter key events for QTextEdit
// We want the editor to be able to process the key press
// before committing the data (e.g. so it can do
// validation/fixup of the input).
#endif // QT_NO_TEXTEDIT
#ifndef QT_NO_LINEEDIT
if (QLineEdit *e = qobject_cast<QLineEdit*>(editor))
if (!e->hasAcceptableInput())
return false;
#endif // QT_NO_LINEEDIT
QMetaObject::invokeMethod(this, "_q_commitDataAndCloseEditor",
Qt::QueuedConnection, Q_ARG(QWidget*, editor));
return false;
case Qt::Key_Escape:
// don't commit data
emit closeEditor(editor, QAbstractItemDelegate::RevertModelCache);
break;
default:
return false;
}
if (editor->parentWidget())
editor->parentWidget()->setFocus();
return true;
} else if (event->type() == QEvent::FocusOut || (event->type() == QEvent::Hide && editor->isWindow())) {
//the Hide event will take care of he editors that are in fact complete dialogs
if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) {
QWidget *w = QApplication::focusWidget();
while (w) { // don't worry about focus changes internally in the editor
if (w == editor)
return false;
w = w->parentWidget();
}
#ifndef QT_NO_DRAGANDDROP
// The window may lose focus during an drag operation.
// i.e when dragging involves the taskbar on Windows.
if (QDragManager::self() && QDragManager::self()->object != 0)
return false;
#endif
emit commitData(editor);
emit closeEditor(editor, NoHint);
}
} else if (event->type() == QEvent::ShortcutOverride) {
if (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Escape) {
event->accept();
return true;
}
}
return false;
}