Nội dung text S3G17 Взаимодействие со средой исполнения. Drag'n'Drop в Qt
Технологии разработки программного обеспечения Приложение с графическим пользовательским интерфейсом Факультет инфокоммуникационных сетей и систем Кафедра программной инженерии и вычислительной техники Петрова О. Б., Резников Б. К. Технологии разработки программного обеспечения S3G17 ВЗАИМОДЕЙСТВИЕ СО СРЕДОЙ ИСПОЛНЕНИЯ. DRAG'N'DROP В Qt ъыъ.рф/еыуъ Цель работы Рассмотреть технологию Drag’n’Drop. Теоретические сведения При работе с технологией Drag'n'Drop следует рассматривать следующие события: • void dragEnterEvent(QDragEnterEvent *) курсор мыши попадает внутрь данного виджета при перетаскивании • void dragLeaveEvent(QDragLeaveEvent *) курсор мыши покидает границы данного виджета при перетаскивании • void dragMoveEvent(QDragMoveEvent *) курсор мыши перемещается внутри границ виджета при перетаскивании • void dropEvent(QDropEvent *) была отпущена кнопка мыши, когда курсор находился в границах данного виджета при перетаскивании • void mouseMoveEvent(QMouseEvent *) курсор мыши перемещается внутри границ виджета • void mousePressEvent(QMouseEvent *) была нажата кнопка мыши, когда курсор находился в границах данного виджета Перетаскивание обычно начинается в следующих случаях: • при нажатии ЛКМ на объекте; • при нажатии ЛКМ на объекте и удержании еѐ в течении некоторого времени (QApplication::startDragTime()); • при нажатии ЛКМ на объекте и перемещении курсора мыши с нажатой клавишей на некоторое расстояние (QApplication::startDragDistance()). Для того что бы выполнить перетаскивание на стороне источника необходимо: 1
Технологии разработки программного обеспечения Приложение с графическим пользовательским интерфейсом Факультет инфокоммуникационных сетей и систем Кафедра программной инженерии и вычислительной техники Петрова О. Б., Резников Б. К. • Создать объект класса QMimeData в динамически распределяемой памяти (с использованием оператора new). Удаляется библиотекой Qt. • Задать созданному объекту передаваемые данные и указать их тип (можно регистрировать свои типы данных). • Создать объект класса QDrag в динамически распределяемой памяти (с использованием оператора new). Удаляется библиотекой Qt. Указать созданному объекту на объект класса QMimeData, содержащий перетаскиваемые данные. • Задать прочие свойства перетаскивания (отображаемый курсор, отображаемое изображение перетаскиваемого объекта, позиция курсора относительно изображения). • Вызвать метод QDrag::exec, указав ему допустимые действия. • Выполнить нужные операции в соответствии с возвращѐнным значением выбранного действия (только те которые надо предпринять на стороне источника). Возможные действия описываются значениями из перечисления Qt::DropAction: • Qt::CopyAction – создание копии перетаскиваемого объекта • Qt::MoveAction – перемещение перетаскиваемого объекта • Qt::LinkAction – создание ссылки перетаскиваемого объекта • Qt::IgnoreAction – отсутствие действия Важные методы в классе QDropEvent: • acceptProposedAction – установить предложенное действие в качестве действия предпринимаемого при “бросании” и принять событие • dropAction – предпринимаемое действие при “бросании” объекта • mimeData – данные перетаскиваемого объекта • possibleActions – возможные действия • proposedAction – предложенное действие • setDropAction – установить действие предпринимаемоепри “бросании” объекта • source – виджет-источник перетаскиваемого объекта, если объект перетаскивается в рамках одной программы • accept – принять событие • ignore– игнорировать событие (игнорируемое событие будет передаваться родительскому виджету) Для того чтобы виджет получал события о перетаскивании над нимнекоторого объекта необходимо выполнить setAcceptDrops(true). Для получения более подробной информации по этой теме изучите документацию по следующим методам и классам: • QAbstractItemView::setDragEnabled 2
Технологии разработки программного обеспечения Приложение с графическим пользовательским интерфейсом Факультет инфокоммуникационных сетей и систем Кафедра программной инженерии и вычислительной техники Петрова О. Б., Резников Б. К. • QWidget::setAcceptDrops • QAbstractItemView::setDropIndicatorShown • QWidget::dragEnterEvent • QWidget::dropEvent • QDragEnterEvent • QDropEvent • QMimeData • QUrl Продемонстрируем работу с этой технологией в Qt на примере приложения, которое моделирует ханойские башни, представляемые виджетом с вертикальным размещением элементов. Каждый диск изображается меткой обозначающей его размер. Интерфейс программы позволяет снимать с башни верхний диск и перемещать его на другую башню так, чтобы под ним не оказался диск меньшего размера. Файл tower.h содержит определение класса Tower, который отвечает за работу отдельной башни. #ifndef TOWER_H #define TOWER_H #include #include #include #include #include /* Класс Tower отвечает за отображение одной из башен и дисков на ней. Кроме того, этот класс отвечает за возможность перетаскивания дисков */ class Tower : public QWidget { Q_OBJECT public: explicit Tower(QWidget *parent = 0); /* Помещает, если допустимо, диск указанного размера на вершину башни*/ bool addDisk(int size); protected: /* Обработка события нажатия кнопки мыши. Определяет начало перетаскивания */ void mousePressEvent(QMouseEvent *); /* Обработка события внесения перетаскиваемого объекта в виджет */ void dragEnterEvent(QDragEnterEvent *event); /* Обработка события бросания в виджет */ void dropEvent(QDropEvent *event); private: 3
Технологии разработки программного обеспечения Приложение с графическим пользовательским интерфейсом Факультет инфокоммуникационных сетей и систем Кафедра программной инженерии и вычислительной техники Петрова О. Б., Резников Б. К. QVBoxLayout *verticalLayout; QSpacerItem *verticalSpacer; QStack diskSizes; bool canPut(int size); bool isAcceptable(const QDropEvent *event); int eventData(const QDropEvent *event, bool *ok); }; #endif // TOWER_H Файл tower.cpp содержит определения методов класса Tower. #include "tower.h" #include #include #include #include #include Tower::Tower(QWidget *parent) : QWidget(parent) { resize(400,300); setAcceptDrops(true); verticalLayout = new QVBoxLayout(this); verticalSpacer = new QSpacerItem(20, 289, QSizePolicy::Minimum, QSizePolicy::Expanding); verticalLayout->addItem(verticalSpacer); } bool Tower::addDisk(int size) { if (!canPut(size)) return false; QString name = QString::number(size); QLabel *disk = new QLabel(name, this); disk->setAlignment(Qt::AlignCenter); verticalLayout->insertWidget(1, disk); diskSizes.push(size); return true; } void Tower::mousePressEvent(QMouseEvent *) { if (diskSizes.empty()) return; QWidget *item = verticalLayout->itemAt(1)- >widget(); QLabel *disk = static_cast(item); QMimeData *diskData = new QMimeData; diskData->setText(disk->text()); int diskWidth = disk->width(); int diskHeight = disk->height(); QPixmap diskPixmap(diskWidth, diskHeight); 4