Qt:Документация 4.3.2/model-view-dnd

Материал из Wiki.crossplatform.ru

Перейти к: навигация, поиск
40px Внимание: Актуальная версия перевода документации находится здесь

__NOTOC__

Image:qt-logo.png

Главная · Все классы · Основные классы · Классы по группам · Модули · Функции

Image:trolltech-logo.png

[Предыдущая: Вспомогательные классы представления элементов ] [ Содержание ] [Следующая: Модели-посредники ]

Содержание

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

[править] Краткий обзор

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

Стандартные представления автоматически поддерживают внутреннюю операцию drag and drop, когда элементы перемещаются внутри области отображения для изменения порядка их отображения. По умолчанию операция 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:

  • Для разрешения перетаскивания элементов, установите свойство представления dragEnabled в значение true.
  • Чтобы разрешить пользователю отпускать внутренние и внешние элементы внутри представления, установите свойство представления acceptDrops в значение true.
  • Чтобы показывать пользователю, куда будет помещен при отпускании перетаскиваемый в настоящий момент элемент, установите свойство представления showDropIndicator. Это позволит предоставлять пользователю непрерывно обновляемую информацию о размещении элемента внутри представления.

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

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

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

Чтобы разрешить пользователю свободно перемещать элементы внутри представления нужно установить dragDropMode виджета-списка:

 listWidget->setDragDropMode(QAbstractItemView::InternalMove);

[править] Использование классов модель/представление

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

 QListView *listView = new QListView(this);
 listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
 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 к элементам

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

Например, модель, предоставляющая простой список, основанный на QAbstractListModel, может позволить использование операции drag and drop для каждого элемента, гарантируя, что возвращаемые флаги содержат значения Qt::ItemIsDragEnabled и Qt:: 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;
 }

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

Так как модель унаследована от QStringListModel, то в вышеприведенном коде мы получили набор флагов по умолчанию вызвав ее реализацию функции flags().

[править] Кодирование экспортируемых данных

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

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

 QStringList DragDropListModel::mimeTypes() const
 {
     QStringList types;
     types << "application/vnd.text.list";
     return types;
 }

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

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

 QMimeData *DragDropListModel::mimeData(const QModelIndexList &amp;indexes) const
 {
     QMimeData *mimeData = new QMimeData();
     QByteArray encodedData;
 
     QDataStream stream(&amp;encodedData, QIODevice::WriteOnly);
 
     foreach (QModelIndex index, indexes) {
         if (index.isValid()) {
             QString text = data(index, Qt::DisplayRole).toString();
             stream << text;
         }
     }
 
     mimeData->setData("application/vnd.text.list", encodedData);
     return mimeData;
 }

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

[править] Вставка отпускаемых данных в модель

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

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

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

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

 bool DragDropListModel::dropMimeData(const QMimeData *data,
     Qt::DropAction action, int row, int column, const QModelIndex &amp;parent)
 {
     if (action == Qt::IgnoreAction)
         return true;
 
     if (!data->hasFormat("application/vnd.text.list"))
         return false;
 
     if (column > 0)
         return false;

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

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

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

     int beginRow;
 
     if (row != -1)
         beginRow = row;

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

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

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

     else
         beginRow = rowCount(QModelIndex());

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

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

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

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

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

     QByteArray encodedData = data->data("application/vnd.text.list");
     QDataStream stream(&amp;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);
         beginRow++;
     }
 
     return true;
 }

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

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

[Предыдущая: Вспомогательные классы представления элементов ] [ Содержание ] [Следующая: Модели-посредники ]



Copyright © 2007 Trolltech Trademarks
Qt 4.3.2