Home · All Classes · Main Classes · Grouped Classes · Modules · Functions

[Предыдущая: Удобные Классы Представлений Элементов] [Содержание] [Следующая: Модели-Посредники]

Использование Drag and Drop с Представлениями Элементов

Обзор

Архитектура модель/представление полностью поддерживает инфраструктуру Qt drag and drop. Элементы списков, таблиц и деревьев могут быть перемещены внутри области отображения, а их данные могут быть импортированы и экспортированы в виде закодированной в MIME информации.

Стандартные виджеты-контейнеры автоматически поддерживают внутреннюю операцию drag and drop, когда элементы перемещаются внутри области отображения для изменения порядка их отображения. По умолчанию для этих представлений не разрешена операция drag and drop, так как они созданы для простого, наиболее частого, их употребления. Для того, чтобы элементы могли перетаскиваться, должны быть включены некоторые свойства представления, а самим элементам должно быть позволено перетаскиваться.

К модели, которая позволяет только экспортировать данные из представления, предъявляются более скромные требования, чем к модели, которая позволяет перетаскивать информацию в себя и требующей полной доступности операций drag and drop.

Использование Удобных Представлений

Каждый тип элементов, используемых в QListWidget, QTableWidget и QTreeWidget, настроен для различных режимов использования с помощью флагов по умолчанию. Например, каждый объект QListWidgetItem или QTreeWidgetItem изначально доступен, переключаем, выбираем и может использоваться как объект операции drag and drop; каждый QTableWidgetItem также может быть редактируемым и использоваться как приемник операции drag and drop.

Несмотря на то, что все стардартные элементы имеют один или оба установленнных флага поддержки drag and drop, Вам, как правило, требуется установить различные свойства самого представления для того, чтобы воспользоваться возможностями встроенной поддержки операций drag and drop:

Например, с помощью следующих строк кода можно включить использование операции drag and drop в виджете-списке:

    QListWidget *listWidget = new QListWidget(this);
    listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
    listWidget->setDragEnabled(true);
    listWidget->setAcceptDrops(true);
    listWidget->setDropIndicatorShown(true);

В результате виджет-список позволит элементам быть скопированным в пределах области отображения и даже быть перемещенными в виджеты, содержащие данные такого же типа. В обоих случаях, элементы будут скорее скопированы, чем перемещены. To move items around

Использование Классов Модель/Представление

Настройка предсталения для использования операции drag and drop происходит тем же образом, что и настройка удобных классов. Например, QListView может быть настроен точно также, как и QListWidget:

    QListView *listView = new QListView(this);
    listView->setSelectionMode(QAbstractItemView::SingleSelection);
    listView->setDragEnabled(true);
    listView->setAcceptDrops(true);
    listView->setDropIndicatorShown(true);

Так как доступ к отображаемым представлением данным управляется моделью, используемая модель также должна предоставлять поддержку операций drag and drop. Действия, поддерживаемые моделью, можно задать повторно реализовав функцию QAbstractItemModel::supportedDropActions(). Например, с помощью следующего кода можно сделать доступными операции копирования и перемещения:

    Qt::DropActions DragDropListModel::supportedDropActions() const
    {
        return Qt::CopyAction | Qt::MoveAction;
    }

Модели можно передать любую комбинацию значений Qt::DropActions, но их поддержку моделью необходимо прописать. Например, для использования должным образом моделью списка значения Qt::MoveAction, модель должна иметь реализацию QAbstractItemModel::removeRows() или непосредственно, или унаследовав ее от базового класса.

Разрешение Применения Drag and Drop к Элементам

Указать представлению, какие элементы могут быть перемещены, а какие могут принять операцию drag and drop, модели могут с помощью повторной реализации, для предоставления подходящих флагов, функции QAbstractItemModel::flags().

Например, модель, предоставляющая простой список, основанный на QAbstractListModel, может позволить использование операции drag and drop для каждого элемента, гарантируя, что возвращаемые флаги содержат значения Qt::ItemIsDragEnabled и Qt::ItemIsDropEnabled:

    Qt::ItemFlags DragDropListModel::flags(const QModelIndex &index) const
    {
        Qt::ItemFlags defaultFlags = QStringListModel::flags(index);

        if (index.isValid())
            return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
        else
            return Qt::ItemIsDropEnabled | defaultFlags;
    }

Обратите внимание на то, что отпускание позволяется только на верхнем уровне модели, а перетаскивание позволяется только для действительных элементов.

Кодирование Экспортируемых Данных

При экспортировании элементов данных с помощью операции drag and drop, они кодируются в формат, соответствующий одному или нескольким типам MIME. Модели декларируют типы MIME, которые они могут применять по отношению к элементам, с помощью повторной реализации функции QAbstractItemModel::mimeTypes(), возвращающей список страндартных типов MIME.

Например, модель, которая предосталяет лишь простой текст, может иметь следующую реализацию данной функции:

    QStringList DragDropListModel::mimeTypes() const
    {
        QStringList types;
        types << "text/plain";
        return types;
    }

Также модель должна иметь код, конвертирующий данные в соответствующий формат. Это достигается с помощью повторной реализации функции QAbstractItemModel::mimeData() предоставляющей объект QMimeData, такой же, как и в любой другой операции drag and drop.

Следующий код показывает, как каждый элемент данных, соответствующей списку индексов, может быть закодирован в виде простого текста и помещен в объект QMimeData.

    QMimeData *DragDropListModel::mimeData(const QModelIndexList &indexes) const
    {
        QMimeData *mimeData = new QMimeData();
        QByteArray encodedData;

        QDataStream stream(&encodedData, QIODevice::WriteOnly);

        foreach (QModelIndex index, indexes) {
            if (index.isValid()) {
                QString text = data(index, Qt::DisplayRole).toString();
                stream << text;
            }
        }

        mimeData->setData("text/plain", encodedData);
        return mimeData;
    }

Так как функции передается список модельных индексов, этот подход достаточно универсален для использования в иерархических и неиерархических моделях.

Вставка Перетаскиваемых Данных в Модель

Способ обработки моделью отпускания данных зависит от типов данных и модели (список, таблица или дерево) и способа представления содержимого пользователю. Вообще, принимаемый для обработки отпускаемых данных подход должен зависеть от основного способа хранения данных.

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

Отпускаемые данные обрабатываются моделью с помощью повторной реализации QAbstractItemModel::dropMimeData(). Например, модель, работающая с простым списком строк, может по различному обрабатывать отпускание данных на существующий элемент и на верхний уровень, т.е. на несуществующий элемент.

Модель сперва должна удостовериться, что операция должна быть выполнена, передаваемые данные имеют формат, который может использоваться, и что их назначение уместно для данной модели:

    bool DragDropListModel::dropMimeData(const QMimeData *data,
        Qt::DropAction action, int row, int column, const QModelIndex &parent)
    {
        if (action == Qt::IgnoreAction)
            return true;

        if (!data->hasFormat("text/plain"))
            return false;

        if (column > 0)
            return false;

Простая модель одноколоночного списка может сообщить об отказе в принятии данных, если перемещаемые данные не являются простым текстом или если переданный при перетаскивании номер колонки недействителен.

Вставляемые в модель данные, в зависимости от того, отпускаются ли они над действительным или над недействительным элементом, обрабатываются по разному. В этом простом примере, когда происходит отпускание между существующими элементами модели верхнего уровня, указанный родительский индекс недействителен, и строка соответсвует строке модели, в которую вставляются элементы:

        int beginRow;

        if (!parent.isValid())
            beginRow = row;
        else
            beginRow = parent.row();

При отпускании над элементом верхнего уровня, указанный родительский индекс действителен, и новые элементы вставляются на верхний уровень модели перед этим элементом.

В иерархических моделях, при отпускании над элементом, новые элементы лучше вставлять в модель в качестве дочерних по отношению к элементу, над которым происходит отпускание. В показанном здесь простом примере модель имеет один уровень, поэтому такой подход здесь неуместен.

Декодирование Импортируемых Данных

Каждая из реализаций dropMimeData() дожна декодировать данные и всталять их в основную структуру модели.

В простой модели списка строк декодированные элементы могут быть направлены в QStringList:

        QByteArray encodedData = data->data("text/plain");
        QDataStream stream(&encodedData, QIODevice::ReadOnly);
        QStringList newItems;
        int rows = 0;

        while (!stream.atEnd()) {
            QString text;
            stream >> text;
            newItems << text;
            ++rows;
        }

Строки могут быть вставлены в основную структуру данных. Чтобы быть последовательными, мы можем это сделать через интерфейс модели:

        insertRows(beginRow, rows, QModelIndex());
        foreach (QString text, newItems) {
            QModelIndex idx = index(beginRow, 0, QModelIndex());
            setData(idx, text);
        }

        return true;
    }

Обратите внимание на то, что модель обычно должна предоставлять реализации функций QAbstractItemModel::insertRows() и QAbstractItemModel::setData().

См. также Item Views Puzzle Example.

[Предыдущая: Удобные Классы Представлений Элементов] [Содержание] [Следующая: Модели-Посредники]


Copyright © 2005 Trolltech Trademarks
Qt 4.1.0
Hosted by uCoz