Drag&Drop в Qt: Перемещение изображения и текста

Drag&Drop в Qt

Перетаскивание с помощью мыши (Drag&Drop) — интуитивно понятный жест, используемый во многих приложениях. Нельзя сказать, что он является наилучшим вариантом организации взаимодействия с программой. Но уметь встраивать подобное поведение в Qt-проекты не помешает.

Постановка задачи

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

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

Второй виджет мы сделаем виджетом-приемником Drop. Он сможет принимать то, что пользователь перетащит из первого виджета.

Базовый виджет

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

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

Реализация imagetextwidget.cpp:

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

Drag-виджет

Виджет-источник, из которого можно перетаскивать текст и изображения, уже поинтереснее. Посмотрим на его заголовочный файл dragwidget.h:

Вся суть заключается в отлавливании событий нажатия кнопки мыши mousePressEvent() и перемещения курсора mouseMoveEvent(). Также обратите внимание на поле типа QPoint. В нем мы будем хранить позицию начала движения.

А вот и реализация dragwidget.cpp:

В функции-члене mousePressEvent() мы всего лишь сохраняем позицию курсора, в которой произошел щелчок. Главное действие происходит в mouseMoveEvent(), которое соответствует перемещению мыши. Сначала мы проверяем, что перетаскивание имеет смысл, т.е. нажата левая кнопка мыши, имеется загруженное изображение и пройденное расстояние от начальной позиции превышает некий минимум, который мы узнаем с помощью QApplication::startDragDistance().

Если все хорошо, то можно создать экземпляр QDrag. При этом информация для перетаскивания помещается в QMimeData. Мы кладем в него изображение и текст (как и планировали). На самом деле, в QMimeData можно передавать вообще все, что угодно. Но об этом в другой раз.

Следующим шагом мы связываем mimeData с drag. Кроме того, для drag устанавливаем изображение, которое будет отображаться при перемещении.

Ключевой момент: QDrag работает по принципу, похожему на модальные диалоговые окна, поэтому для его использования вызываем drag->exec(). В качестве параметра передаем Qt::MoveAction (есть и другие варианты, но их в этот раз трогать не будем).

Если виджет-приемник (которым мы сейчас займемся) успешно принял данные, то drag->exec() вернет Qt::MoveAction. Это означает, что перемещение прошло успешно, поэтому просто очищаем изображение и текст, которые здесь больше не нужны.

Drop-виджет

Реализация виджета-приемника проще, чем для виджета-источника. Убедимся в этом сами. И начнем, как обычно, с заголовочного файла dropwidget.h:

Обработка вновь основана на событиях. Для этого мы переопределяем функции-члены dragEnterEvent() и dropEvent(). Посмотрим, что в них происходит (файл dropwidget.cpp):

Обработчик события dragEnterEvent() срабатывает, когда курсор мыши, «заряженный» данными виджета-источника, оказывается над виджетом-приемником. Сначала мы выводим на консоль список форматов данных, которые содержит в себе событие.

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

Однако главная задача dragEnterEvent() заключается в том, чтобы решить, нужно ли принимать перетаскиваемое содержимое или нет. Проверка осуществляется с помощью функций event->mimeData()->hasImage() и event->mimeData->hasText(). Если проверка пройдена, то для подтверждения достаточно вызвать event->acceptProposedAction().

Обработчик события dropEvent() вызывается в самый ответственный момент, т.е. когда перемещаемое вложение «приземляется» на виджет (в момент отпускания левой кнопки мыши над ним). В этом случае мы просто устанавливаем изображение и текст для отображения в виджете-приемнике. Кроме того, не забудьте про вызов event->acceptProposedAction(). Таким образом мы сообщаем виджету-источнику, что успешно приняли его содержимое.

Собираем приложение

А теперь организуем запуск нашей программы. Файл main.cpp:

Выводы

Мы рассмотрели лишь самый минимум возможностей, которые предоставляет Qt для реализации обработчиков Drag&Drop. Но этого уже хватит для решения большинства стандартных задач.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий