【问题标题】:How to combine modal dialog editor and in-place widget editor in QModelViews?如何在 QModelViews 中结合模态对话框编辑器和就地小部件编辑器?
【发布时间】:2014-11-28 01:02:15
【问题描述】:

我有一个包含简单和复杂数据的模型,我希望使用就地小部件来编辑简单数据,但使用模式对话框来编辑复杂数据......我怎样才能以一种简洁的方式实现这一点? (我真的更喜欢通过 QItemDelegate 的子类来做所有事情,而不是查看特定的 hack)

【问题讨论】:

    标签: c++ qt model-view-controller delegates


    【解决方案1】:

    我认为您必须对视图进行子类化并覆盖 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;
            }
        }
        [..]
    };
    

    【讨论】:

    • 我不想像所说的那样是特定于视图的(委托可以被赋予多个视图)
    • @hl037_,同一个子类也可以用于多个视图。在创建树视图或其他任何内容时使用MyView。委托的问题是您必须提供一个将在您的视图中显示的小部件,但它不能是模式对话框。
    • 只是为了完成这个好答案:如果您决定覆盖视图的 edit() 成员函数,请注意 Qt 通常会在 edit() 中执行的一些检查需要手动完成。特别是,需要检查编辑触发器和索引标志,以确保仅当所选项目可编辑并且仅根据您配置的触发器(例如双击)时才显示编辑器对话框。为此,只需检查editTriggers() & triggerindex.flags() & (Qt::ItemIsEditable | Qt::ItemIsUserCheckable) 是否为真。
    【解决方案2】:

    尝试下一个委托。我在示例中展示了主要思想:

    标题:

    #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++11CONFIG += c++11.pro 文件)和new syntax of signals and slots

    【讨论】:

    • 您的解决方案不完整,但差不多:考虑到此错误:bugreports.qt-project.org/browse/QTBUG-11908 和此博客条目:blogs.kde.org/node/3919,我正在研究它。 QItemDelegate::editorEvent 必须在 else 子句中调用,因为它会在模态对话框之后提供一个编辑器,并且会因为失去焦点而导致应用程序崩溃(这将破坏默认的编辑器小部件......所以当再次访问时,繁荣)
    • @hl037_ 我测试了这段代码,它可以按你的意愿工作,Qt 5.2.0,我开始编辑,出现对话框我输入数据,按确定,数据出现在我的模型和视图中。跨度>
    • 正如预期的那样:在 Archlinux(内核 Linux 3.17.3-1-ARCH)和 Qt 5.3.2 上的 SIGSEGV。这取决于平台:应该在 Windows 上工作,但在 Linux 和 Mac 上崩溃(如我上面写的两个链接中所述)
    • @hl037_ 在这种情况下很抱歉 :(
    • 没问题 ;) 只是在if 中添加一个return true;(它是导致错误的return false),并使用QPointer 来存储直径。然后它应该工作。 (还需要添加一个测试来检查它是否是引起事件的双击,但这是特定于用户的)......但是正如您所经历的那样,这个解决方案非常危险,但它似乎是唯一可以解决问题的方法
    【解决方案3】:

    这是一个老问题,但鉴于这两个答案都不令人满意(返回 false 时崩溃、嵌套事件循环等)... 请注意,我并没有责怪海报上说“不能这样干净地完成”。

    完全不同的受支持方法怎么样?

    我之前有一个这样的实现(伪代码):

    1. 禁用“复杂”项目的编辑触发器

    .

    auto item = model->item(row, column);
    item->setFlags(item->flags() & ~Qt::ItemFlag::ItemIsEditable); // not editable
    
    1. 连接到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();
      }
    
    }
    
    1. 物品委托: 忽略“复杂”项目。

      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);
      }
      

    现在这当然不如只有代理那么好,但至少它不会在崩溃时如此紧密地避开。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-03
      • 1970-01-01
      • 1970-01-01
      • 2016-12-18
      • 1970-01-01
      • 1970-01-01
      • 2013-03-05
      相关资源
      最近更新 更多