没有为拖放调用QStandardItem :: clone()

时间:2011-08-17 05:21:15

标签: qt drag-and-drop

我有一个Qt应用程序,我使用QStandardItemModel派生类和QTreeView与它进行交互。我想启用拖放功能来复制和移动模型周围的项目。为此,我做了以下工作:

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

拖放的工作范围是它可以跟踪哪些项目可以拖动以及哪些项目可以接受丢弃。但是,移动或复制它不会使用我的clone()函数创建新项目。它只复制QStandardItem基类可用的设置和数据,丢失子类覆盖等。

如何获取模型和视图以使用我的clone()函数,或解决此问题?

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

我认为我已经找到了一项工作,或多或少地做了我期望框架做的事情。

标题文件:

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

对于我的应用程序,我可能会添加一个自定义项类,其功能是接受或拒绝特定项,模型查询而不是简单地转储到接受丢弃的任何内容,但对于主要问题,这很好。

答案 1 :(得分:1)

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