【问题标题】:How does QLineEdit triger QAbstractItemDelegate::commitDataQLineEdit 如何触发 QAbstractItemDelegate::commitData
【发布时间】:2015-05-05 20:58:06
【问题描述】:

我正在使用QTreeViewQAbstractItemModel 开发一个Qt 应用程序。 该模型包含一些异构数据,需要不同的控制进行编辑。我通过自定义委托来实现它,该委托查询 model.data(Qt::EditRole) 并且模型将返回 QWidget 以用作编辑器。

我喜欢 QLineEdit 的工作方式 - 当我按下回车键时,delegate::setModelData 会被自动调用,所以我确实不必必须将 QLineEdit::editingFinished 连接到 QAbstractItemDelegate::setModelData(),这非常方便,因为 QLineEdit 从模型以QWidget 的形式返回给委托,并且它不必关心它是什么类型的小部件。 使用QComboBox 有点棘手 - 我希望组合框在选择完成后提交,到目前为止我只能通过connect(myComboBox, SIGNAL(activated(QString)), myDelegate, commitData())); 来完成它 但是,我的委托不知道编辑器小部件的类型,并且我不想为模型最终传递它的每个新编辑器编辑委托的代码。当在连接到其activated() 信号的插槽中单击输入时,我真的想强制组合框执行与 QLineEdit 相同的操作。

那么,QLineEdit 调用委托的setModelData 做什么? Qt 中是否有一种通用的方式用于编辑器,无论是说“我完成了编辑,获取数据并将其传递给模型”?

【问题讨论】:

    标签: qt delegates qlineedit qabstractitemmodel


    【解决方案1】:

    QStyledItemDelegate(和QItemDelegate)定义了一个事件过滤器,如果您按 Tab 或回车,该过滤器将调用 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;
    }
    

    【讨论】:

    • 谢谢,Titusjan,对我来说,下面的方法成功了: void CommittingCombo::_activated(const QString&) { static_cast(parent())->setFocus(); QEvent e(QEvent::FocusOut); QApplication::sendEvent(this, &e);不过,有趣的是,为什么在将焦点转移到父级后我必须发送丢失的焦点事件 - 我希望它会自动发生......
    猜你喜欢
    • 2013-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多