QStandardItem :: clone () не вызывается для перетаскивания - PullRequest
1 голос
/ 17 августа 2011

У меня есть приложение Qt, где я использую производный класс QStandardItemModel и QTreeView для взаимодействия с ним. Я хотел бы включить перетаскивание, чтобы копировать и перемещать элементы по модели. Чтобы сделать это, я сделал следующее:

  • В подклассах QStandardItem, которые представляют конечные узлы: setDragEnabled (true) и override clone () для возврата реальной копии элемента.
  • В узлах папки: setDropEnabled (true)
  • В QTreeView: setDragEnabled (true); setAcceptDrops (истинный); setDropIndicatorShown (истина);

Функция перетаскивания работает в той степени, в которой она учитывает, какие предметы можно перетаскивать, а какие могут принимать капли. Тем не менее, перемещение или копирование не приводит к созданию новых элементов с использованием моих функций clone (). Он только копирует настройки и данные, доступные базовому классу QStandardItem, теряя переопределения подкласса и тому подобное.

Как заставить модель и представления использовать мои функции clone () или обойти это?

Спасибо за любую помощь.

Ответы [ 2 ]

2 голосов
/ 19 августа 2011

Я думаю, что нашел решение, которое более или менее соответствует тому, что я ожидал от Framework.

Заголовочный файл:

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 голос
/ 17 августа 2011

Вы проверили, что ваш прототип clone () соответствует базовому классу?У меня была похожая проблема с sizeHint, который не вызывался при разметке.Проблема была в отсутствующем модификаторе const.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...