【问题标题】:QStandardItem::clone() not being called for Drag and DropQStandardItem::clone() 没有被调用拖放
【发布时间】:2011-08-17 05:21:14
【问题描述】:

我有一个 Qt 应用程序,我使用 QStandardItemModel 派生类和一个 QTreeView 与之交互。我想启用拖放以在模型周围复制和移动项目。为此,我执行了以下操作:

  • 在代表叶节点的 QStandardItem 子类中:setDragEnabled(true) 并覆盖 clone() 以返回项目的真实副本。
  • 在文件夹节点中:setDropEnabled(true)
  • 在 QTreeView 中:setDragEnabled(true); setAcceptDrops(true); setDropIndicatorShown(true);

Drag and Drop 的工作原理是它尊重哪些项目可以拖动以及哪些项目可以接受放置。但是,无论是移动还是复制它都不会使用我的 clone() 函数创建新项目。它只复制 QStandardItem 基类可用的设置和数据,丢失子类覆盖等。

如何让模型和视图使用我的 clone() 函数,或者解决这个问题?

感谢您的帮助。

【问题讨论】:

  • 我知道这是一个旧线程,但我在其他任何地方都没有看到此功能正确记录。 clone() 仅在您通过 QStandardItemModel::setItemPrototype 设置原型时调用,然后仅调用原型对象中的 clone 实现。模型不会对模型中已有的对象调用clone,例如在移动或复制操作期间,尽管这样做真的很方便。顺便说一句,您的解决方案效果很好。

标签: qt drag-and-drop


【解决方案1】:

我想我找到了一种解决方法,它或多或少地完成了我期望框架做的事情。

头文件:

class QextDragDropModel : public QStandardItemModel
{
public:
    /**
     * Uses the passed indexes, and encodes a list of QStandardItem pointers into
     * the mime data.
     */
    virtual QMimeData* mimeData(const QModelIndexList &indexes) const;

    /**
     * Decodes the mimedata, and uses the each QStandardItem::clone() implmentation
     * to place a copy at the requested position of the model.  If it is a move
     * operation Qt will remove the previous item.
     */
    virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action,
                              int row, int column, const QModelIndex &parent);

};

实现:

QMimeData* QextDragDropModel::mimeData(const QModelIndexList &indexes) const
{
    // Need to have the base function create the initial mimeData.
    // It apparently puts something in there that makes Qt call dropMimeData().
    QMimeData* mimeData = QStandardItemModel::mimeData(indexes);

    // The raw data that will be placed in the mimeData.
    QByteArray mimeBytes;

    // Scope the data stream.
    {
         QDataStream ds(&mimeBytes, QIODevice::WriteOnly);

         // The first item encoded will be the number of pointers to expect.
         ds << quint32(indexes.size());

         // Now for each index get a pointer to the standardItem, and write
         // itto the datastream.
         for (int i = 0; i < indexes.size(); i++)
         {
              QStandardItem* ptrItem = itemFromIndex(indexes[i]);
              ds.writeRawData((const char*)&ptrItem, sizeof(QStandardItem*));
         }
    }

    // Add the encoded standard item pointers into the mimeData.
    mimeData->setData("Qt/QStandardItemArray", mimeBytes);

    return mimeData;
}

bool QextDragDropModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
                                     int row, int column, const QModelIndex &parent)
{
    // Get the QStandardItem target of the drop.
    QStandardItem* target = itemFromIndex(parent);

    // If the target is valid, accepts drops and the mimedata has QStandardItem pointers
    // go ahead with decode and insertion.  (Checking drop enabled pobably already
    // done by the framework before calling this function.)
    if ( NULL != target && target->isDropEnabled() && data->hasFormat("Qt/QStandardItemArray") )
    {
         // Fetch the encoded bytes, create a data stream for decoding,
         // and variables to store the output.
         QByteArray indexListBytes = data->data("Qt/QStandardItemArray");
         QDataStream ds(&indexListBytes, QIODevice::ReadOnly);
         quint32 numItems = 0;

         // Get the number of items, allocate memory to store pointers to
         // them and read the pointer data into that memory.
         ds >> numItems;
         int byteLen = numItems*sizeof(QStandardItem*);
         QStandardItem** stdItems = (QStandardItem**)malloc(byteLen);
         ds.readRawData((char*)stdItems, byteLen);

         // Add items to the target at a specific child index if requested,
         // using thier clone() function to create the items.
         for (int i = 0; i < numItems; i++)
         {
             if ( 0 <= row )
                  target->insertRow(row, stdItems[i]->clone());
              else
                  target->appendRow(stdItems[i]->clone());
         }

         // Free memory allocated to store item pointers.
         free(stdItems);

         return true;
    }

    return false;
}

对于我的应用程序,我可能会添加一个自定义项目类,该类具有接受或拒绝特定项目的功能,模型会查询它而不是简单地转储到任何接受掉落的东西中,但对于主要问题,这很好。

【讨论】:

    【解决方案2】:

    您是否检查过您的 clone() 原型与基类中的原型是否匹配?我对 sizeHint 也有类似的问题,在布局期间没有调用它。问题是缺少const 修饰符。

    【讨论】:

    • 这是我的函数原型。对于这样的东西,我从文档中复制并过去。 - 虚拟 QStandardItem* clone() const;
    • 好的,所以这应该不是问题。你是如何实例化你的类的?实例是如何保存的?
    • 我假设您的意思是在 clone() 覆盖中。在那里,我在 (*this) 上调用了我的自定义 QStandardItem 子类的复制构造函数,并将其作为返回值传递。 (这当然包括初始化项目特定的功能,但随后框架从未调用克隆。)至于模型和初始化,我仔细检查了原始问题中的所有内容。
    猜你喜欢
    • 2014-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多