Перетаскивание объектов


Содержание

Перетаскивание объектов в canvas

Im ищет простой в использовании метод присвоения поведения перетаскивания нескольким объектам (изображениям, фигурам и т. д.) В canvas. Кто-нибудь имеет хороший способ или знает какие-либо библиотеки для перетаскивания объектов? Спасибо

5 ответов

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

вы можете создавать перетаскиваемые изображения, такие как:

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

произошла ошибка при перетаскивании нескольких изображений. вот новая версия.

еще одна вещь, которую вы можете проверить, это easeljs это своего рода в стиле AS3. события mouseevent перетаскивание и т. д.

HTML Canvas-в отличие от SVG или HTML-использует не сохраняется (или немедленно) графический API. Это означает, что когда вы рисуете что-то (например, изображение) на холсте, никакого знания об этой вещи не остается. Единственное, что осталось, это пиксели на холсте, смешанные со всеми предыдущими пикселями. Вы не можете перетащить подмножество пикселей; во-первых, пиксели, которые были » под » них ушли. Что вам нужно сделать, это:

  1. трек mousedown событие и посмотрите, находится ли он в «правильном» месте для перетаскивания. (Вам нужно будет отслеживать, какие изображения / объекты находятся там и выполнять обнаружение попадания мыши.)
  2. когда пользователь перетаскивает мышь, перерисуйте весь холст с нуля, рисуя изображение в новом месте каждый раз на основе смещения между текущим местоположением мыши и начальным местоположением mousedown.

некоторые альтернативы, которые я мог бы предложить:

  • SVG
  • чистый HTML-код
  • несколько слоистых холстов и перетащите один прозрачный холст на другой.

HTML Canvas хорош для многих вещей. Взаимодействие пользователя с» элементами», которые кажутся отличными (но не являются), не является одной из этих вещей.

обновление: вот несколько примеров, показывающих перетаскивание холст:

однако ни один из них не создал отдельную библиотеку для отслеживания ваших фигур.

Справка

Перетаскивание мышкой — это простейший способ переместить объект. Используйте этот метод, когда у вас есть только общее представление о том, где должен находиться объект. С помощью инструмента Редактировать (Edit) выберите и перетащите пространственный объект.

Используйте инструмент Редактировать или инструмент Редактировать аннотацию (Edit Annotation), чтобы перемещать объекты аннотаций. Инструмент Редактировать аннотацию активирует функциональность, специфичную для редактирования объектов аннотаций.

  1. Щелкните инструмент Редактировать на панели инструментов Редактор .
  2. Щелкните объект или объекты, которые вы хотите переместить. Щелкая объекты, удерживайте клавишу SHIFT , чтобы выделить несколько пространственных объектов.
  3. Переместите объект или объекты в необходимое местоположение.

Перемещение и копирование объектов

На этой странице

Перемещение объектов при помощи перетаскивания

Чтобы переместить объект, перетащите его в новое место.

Чтобы скопировать объект и переместить копию, во время перетаскивания удерживайте нажатой клавишу «Alt» (Windows) или «Option» (Macintosh).

Чтобы ограничить движение объекта углами, кратными 45°, во время перетаскивания удерживайте нажатой клавишу «Shift».

Перемещение объектов с помощью клавиш со стрелками

Чтобы объект перемещался на 1 пиксел за одно нажатие, нажмите клавишу со стрелкой, соответствующую направлению перемещения.

Чтобы объект перемещался на 10 пикселов за одно нажатие, при нажатии клавиши со стрелкой удерживайте нажатой клавишу «Shift».

Если выбран параметр «Привязать к пикселам», то клавиши со стрелками перемещают объект с приращениями, равными растровой сетке документа, а не пикселам экрана.

Перемещение объектов с помощью инспектора свойств

Значения указываются относительно левого верхнего угла рабочей области.

Инспектор свойств использует единицы измерения, заданные параметром «Единицы измерения линейки» в диалоговом окне «Свойства документа».

Перемещение объектов с помощью панели «Информация»

Значения указываются относительно левого верхнего угла рабочей области.

Перемещение и копирование объектов вставкой

Метод вставки позволяет копировать или перемещать объекты между слоями, монтажными кадрами или другими файлами Animate. Объект может быть вставлен с некоторым смещением относительно исходного.


Копирование объектов с помощью буфера обмена

При копировании элементов в буфер обмена они сглаживаются и поэтому в других приложениях будут выглядеть так же хорошо, как и в программе Animate. Эта функция полезна для кадров, включающих растровые изображения, градиенты, прозрачность или маскирующие слои.

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

Текст из текстового редактора становится единым текстовым объектом.

Векторная графика из любой программы рисования становится группой объектов, которые могут быть разгруппированы и отредактированы.

Растровое изображение становится единым сгруппированным объектом, как и любые импортируемые растровые изображения. Вставленные растровые изображения могут быть разделены или преобразованы в векторную графику.

Прежде чем вставлять в приложение Animate графические объекты из Illustrator, преобразуйте цвета в цветовое пространство RGB.

Копирование трансформированных объектов

Копия объекта может быть создана с масштабированием, поворотом или наклоном.

AutoCAD

Знания

Изучите основы и оттачивайте навыки для повышения эффективности работы в AutoCAD

Не удалось извлечь оглавление

Перемещение объектов

Можно переместить объекты, расположив их на определенном расстоянии и в определенном направлении от исходных объектов.

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

Указание расстояния с помощью двух точек

Переместите объект, используя расстояние и направление, указанное базовой точкой, за которой следует вторая точка. В следующем примере производится перемещение блока, представляющего окно. Выберите объект для перемещения (1). Укажите базовую точку для перемещения (2), за которой следует вторая точка (3). Объект перемещается на расстояние и в направлении от точки 2 к точке 3.

Использование операции «Растянуть-Переместить»

Для перемещения объектов, расположенных полностью внутри рамки выбора, можно использовать команду РАСТЯНУТЬ. Включите режим «Орто» или полярного отслеживания для перемещения объектов в заданном направлении.

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

В результате необходимо захватить рамкой весь объект для перемещения.

Перетаскивание, редактирование с помощью ручек или сдвиг объектов

Быстрое перемещение выбранных объектов путем перетаскивания, редактирования с помощью ручек или сдвига.

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

Для сдвига выбранных объектов с ортогональными приращениями нажмите CTRL + клавиши со стрелками. Режим привязки влияет на расстояние и направление, в котором объекты сдвигаются.

  • Сдвиг объектов при отключенном режиме привязки: объекты перемещаются на два пикселя за один раз; перемещение является относительным и ортогональным к экрану, независимо от направления вида и ориентации ПСК.
  • Сдвиг объектов при включенном режиме привязки: объекты перемещаются с заданным приращением согласно текущему расстоянию привязки; перемещение ортогонально к осям X и Y текущей ПСК и соотносится с направлением вида.

4.4.4. Выделение и перетаскивание

4.4.4. Выделение и перетаскивание

Довольно часто при работе с компьютером приходится выделять группы объектов. Например, вы хотите переместить группу файлов. Намного проще выделить ее и переместить куда нужно, чем перемещать по одному файлу.

Существует несколько способов выделения объектов:

Последовательное выделение мышью — используется для выделения последовательно расположенных объектов. Данный способ заключается в следующем. Подводите указатель мыши к первому объекту группы. Указатель нужно поместить возле объекта, но не на объект, иначе вы начнете перетаскивать объект, а нам это не нужно. Итак, помещаем указатель возле объекта. Нажимаем левую кнопку мыши и, не отпуская ее, перемещаем мышь, пока не захватим все нужные объекты. На рис. 35 показан сам процесс выделения, а именно область выделения. По окончании выделения объектов можно отпустить левую кнопку. Группа объектов будет выбрана. Далее можно щелкнуть правой кнопкой мыши на одном из объектов группы и выбрать операцию. Но об этом позже.

Последовательное выделение с помощью клавиатуры и мыши — если сразу выделить объекты с помощью мыши не получается (ну не слушается «зверь»!), то можно использовать следующий способ. Нажмите Shift, не отпуская ее, щелкните по первому объекту группы, затем сразу же щелкните по последнему объекту группы, отпустите Shift. Будут выделены все объекты, которые расположены между первым и последним объектом.

Выборочное выделение — данный способ используется, если объекты расположены непоследовательно: например один — в начале списка, другой — в середине и еще два — в конце. Выборочное выделение осуществляется с помощью клавиши Ctrl. Нажмите Ctrl, не отпуская ее, щелкните на первом объекте, затем — на втором и т. д. Когда выделите последний объект, можно отпустить Ctrl.

Рис. 35. Область выделения.

Перетаскивание осуществляется только с помощью мыши. Щелкните по объекту, который вы хотите перетащить и, не отпуская левую кнопку мыши, перетащите объект в нужное место. После этого можете отпустить левую кнопку мыши. Если во время перетаскивания держать нажатой клавишу Ctrl, то будет произведена операция копирования, а не перемещения объекта. То есть будет создана копия объекта, которую вы сможете перетащить на другое место, а исходный объект останется на старом месте. В случае копирования указатель мыши немного видоизменит свою форму: рядом со стрелкой появится знак «+» в белом квадратике— это признак копирования.

Qt/C++ — Урок 023. Перетаскивание QGraphicsItem на QGraphicsScene мышью

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


Давайте разберёмся, как это сделать.

Структура проекта

Для демонстрации примера создаём новый проект и добавляем в него новый класс, отнаследованный от QGraphicsItem .

  • MoveGraphicsItem.pro — профайл проекта;
  • main.cpp — запускающий файл;
  • widget.h — заголовочный файл главного окна;
  • widget.cpp — файл исходных кодов главного окна;
  • moveitem.h — заголовочный файл графического элемента;
  • moveitem.cpp — файл исходных кодов графического элемента.
  • widget.ui — форма главного окна.

widget.ui

В форму главного окна помещаем два объекта:

  • QGraphicsView — будет содержать графическую сцену;
  • QPushButton — будет создавать новые графические объекты.

widget.h

В заголовочном файле главного окна лишь объявляем графическую сцену и слот для кнопки.

widget.cpp

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

Илон Маск рекомендует:  Загрузка файла на сервер перетаскиванием Drag and Drop с использованием AJAX+PHP+JavaScript

moveitem.h

Для осуществления красивого перетаскивания графических объектов Нам понадобится использовать функции mouseMoveEvent , mousePressEvent и mouseReleaseEvent . В функции mouseMoveEvent будет производиться непосредственное перетаскивание графического объекта, а в двух других будет производиться смена внешнего вида курсора мыши, которые будет сигнализировать о том, что мы берём и отпускаем графический объект.

moveitem.cpp

Графический объект будет представлять собой обычный зеленый квадрат.

Итог — осуществляем перетаскивание

В результате у Вас должно получиться приложение, в котором по нажатию кнопки динамически создаваться зелёный квадрат в случайном месте графической сцены. И Вы сможете осуществлять его перетаскивание при помощи мыши.

Демонстрацию работы приложения Вы можете увидеть в видеоуроке.

Ссылка на скачивание проекта в zip-архиве: MoveGraphicsItem

Видеоурок

Рекомендуем хостинг TIMEWEB

Рекомендуемые статьи по этой тематике

Подписчики

Платёжная система
  • Евгений Легоцкой
  • 28229
  • 39
  • 1
  • 0
  • damix
  • #
  • 15 июня 2020 г. 21:39


Лучше где-то в классе MoveItem объявить

А потом
Иначе движение получается неестественное. Дергается при клике.

  • Евгений Легоцкой → damix
  • #
  • 16 июня 2020 г. 12:15

Не, не совсем так. Здесь нужно будет учитывать сдвиг позиции курсора относительно координаты (0, 0) в координатной системе MoveItem.

Получается тогда так:

Координаты сдвига объявляем в private секции MoveItem

А в методах учитываем этот сдвиг следующим образом:

  • Mark
  • #
  • 28 июня 2020 г. 15:44

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

  • damix → Mark
  • #
  • 29 июня 2020 г. 14:39

Надо просто где-то хранить указатели на графические элементы, в списке, векторе или массиве. В widget.cpp в методе

надо указатель item сохранять. Объявить у класса widget в private-секции например QVector v, а потом v.append(item). И обращаться к ним, как к элементам вектора.

  • Mark → damix
  • #
  • 29 июня 2020 г. 17:31
  • Евгений Легоцкой → Mark
  • #
  • 30 июня 2020 г. 22:13

Если перед обращением графические объекты выбирались мышью, то можно использовать метод selectedItems() у QGraphicsScene. Этот метод можно использовать в том случае, когда у графических объектов устанавливается флаг ItemIsSelectable. Тогда, если вам необходимо что-то делать с выделенными объектами, то может и не понадобиться хранить графические объекты в отдельном векторе.

  • Mark → Евгений Легоцкой
  • #
  • 4 июля 2020 г. 0:32

  • damix
  • #
  • 5 июля 2020 г. 22:17

Одним методом setFlag решить всю задачу. И тогда события mouseMoveEvent, mousePressEvent и mouseReleaseEvent можно даже не переопределять.

  • Евгений Легоцкой → damix
  • #
  • 5 июля 2020 г. 23:07

Да, это стандартный вариант для перемещения элементов в Qt. Но установка флага не всегда помогает для создания перемещаемого элемента. Например, переопределение методов mouseMoveEvent, mousePressEvent и mouseReleaseEvent позволит сделать кастомный интерфейс самого приложения, как например здесь .

  • Mark → Евгений Легоцкой
  • #
  • 13 июля 2020 г. 1:26

Подскажите пожалуйста как в данном проекте по перетаскиванию организовать удаление объекта со scene методом delete item, допустим при щелчке ПКМ по объекту QGraphicsScene. Мои попытки оказались тщетными (маны пока маловато наверное). Заранее спасибо.

  • Евгений Легоцкой → Mark
  • #
  • 13 июля 2020 г. 2:12

Ну например так можете сделать.

Не забудьте только подключить QApplication в файле через #include

И используйте deleteLater(), тогда объект будет удалён тогда, когда он не будет использоваться.

  • mihenze
  • #
  • 8 октября 2020 г. 16:24

Добрый день. У меня возник такой вопрос: Каким образом в данном примере можно организовать выделение объекта? Просто setSelected метод QGraphicsScene, а мы переопределяли методы для работы с мышью в QGraphicsItem. Так как правильно это реализовать(варианты реализации которые я вижу): 1 вариант — переопределить методы мышки для QGraphicsScene, 2 вариант -эмитировать сигнал в методе мышки QGraphicsItem, который запустит slotSelected в QGraphicsScene, 3 вариант — передать указатель на QGraphicsScene в QGraphicsItem. Или может можно сделать все проще?

  • Евгений Легоцкой → mihenze
  • #
  • 8 октября 2020 г. 16:58


Смотрите, какой здесь момент. Эта статья писалась с расчётом на альтернативный вариант того, как можно сделать перемещение объектов на графической сцене. Фактически, если использовать флаги ItemIsMovable , ItemIsSelectable в самом QGraphicsItem, то не понадобится никаких переопределений методов. Просто в некоторых ситуациях, когда не хватает функционала Qt, приходится делать переопределение методов и писать логику всех этих перемещений и выделений.

  • mihenze → Евгений Легоцкой
  • #
  • 8 октября 2020 г. 18:32

Пробую реализовать на вашем примере, установил флаги, даже убрал реализацию методов мышки из класса, все равно ItemIsSelectable не срабатывает, при том что ItemIsMovable работает. Так же попробовал дописать в методы мышки вызов методов базового класса QGraphicsItem::mousePress(Move, Release)Event(event); — все равно не срабатывает. Поэтому возник еще один вопрос, правильно ли я понимаю, что при выделении должен контур штрихом перерисовываться или визуально никаких отображений видно не будет?

  • Евгений Легоцкой → mihenze
  • #
  • 8 октября 2020 г. 18:48

Вообще, если просто удалить все переопределённые методы мыши из графических объектов, то выделение должно работать. А границы будут перерисовываться пунктирной линией. Так что, Вы на правильном пути.

  • mihenze → Евгений Легоцкой
  • #
  • 8 октября 2020 г. 19:28

Реализовал с помощью setSelected в обработке клика и добавления условия в paint. Но попутно возник вопрос если у меня например на сцене два объекта, один из них выделен, я щелкаю по второму, чтобы выделить его, как снять выделение с 1? 1 вариант — сохранять указатель на пред. элемент и выставлять значение setSelected в false. 2 вариант — получать выделенный при помощи selectedItems() сцены, и все остальные элементы отмечать как false.

  • Евгений Легоцкой → mihenze
  • #
  • 8 октября 2020 г. 19:47

я как-то писал небольшой векторный редактор в качестве тестового задания, и насколько помню, хранил в векторе указатели на выделяемые объекты (не просто один указатель, а век тор указателей). Так что предложенный вам вариант вполне адекватен на мой взгляд. Плюс имеется возможность контролировать варианты выделения с использованием клавиш CTRL или SHIFT, чтобы например добавлять объекты к выделенным.

  • mihenze
  • #
  • 9 октября 2020 г. 22:10

Добрый вечер. Продолжаю переделывать ваш пример. Возникло 2 вопроса:

  • Евгений Легоцкой → mihenze
  • #
  • 10 октября 2020 г. 2:47
  • mihenze → Евгений Легоцкой
  • #

  • 10 октября 2020 г. 21:10

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

  • Евгений Легоцкой → mihenze
  • #
  • 10 октября 2020 г. 21:19
  • avovana
  • #
  • 11 мая 2020 г. 16:10

Подскажите, пожалуйста, как сделать чтобы при нажатие на квадрат и переносе квадрата курсор фиксировался в месте нажатия квадрата? Точнее — центр квадрата не смещался в точку нажатия.

  • damix → avovana
  • #
  • 11 мая 2020 г. 17:20
  • avovana
  • #
  • 11 мая 2020 г. 18:00

спасибо за наводку, изучаю.

  • avovana
  • #
  • 11 мая 2020 г. 18:07

Заработал первый вариант.

  • damix → avovana
  • #
  • 11 мая 2020 г. 18:37

У меня оба работали. Но я во втором способе удалил (закомментировал) переопределенные функции и походу в этом дело.


  • Мария Типикина
  • #
  • 30 августа 2020 г. 11:36

Добрый день. Подскажите, пожалуйста, как быть, если вместо зеленых квадратов мне нужно перемещать изображение QPixmap? Где его определить и как добавить на сцену? если делаю просто scene->addPixmap(myPixmap); то ничего не работает — фото не перемещается. Заранее спасибо!

  • damix → Мария Типикина
  • #
  • 30 августа 2020 г. 17:35
  • Мария Типикина → damix
  • #
  • 31 августа 2020 г. 8:02

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

  • damix → Мария Типикина
  • #
  • 31 августа 2020 г. 17:48
  • damix → Мария Типикина
  • #
  • 1 сентября 2020 г. 15:04
  • Мария Типикина → damix
  • #
  • 4 сентября 2020 г. 8:03

Вот как раз так я и делала — меняла только этот метод, у меня не сработало. Видимо где-то еще я набедокурила. Спасибо Вам!)

  • damix → Мария Типикина
  • #
  • 4 сентября 2020 г. 20:56
  • Мария Типикина → damix
  • #
  • 11 сентября 2020 г. 11:32

нет, пишу мини фото-редактор, чтобы фото можно было зуммировать и перемещать в окне, когда оно все не влазит (большой масштаб)

  • Egor Fomin
  • #
  • 13 июня 2020 г. 13:24

Добрый день. Передо мной стоит схожая с данным примером задача — мне надо реализовать возможность добавлять сплайн-аппроксимацию на загруженном изображении и я хочу, чтобы пользователь мог корректировать полученную кривую вручную. Кривая формируется из точек и соединяющих эти точки кривых(QGraphicsPathItsm в моем случае). Для описания точек у меня есть отдельный класс, который так же, как и в примере, унаследован от QGraphicsItem и QObject. Меня устраивает поведение этих точек, если добавить их на сцену. Второй класс содержит QList этих точек, там все точки хранятся. В этом классе так же находится QList кривых, соединяющих эти точки. Моя задача — изменять положение криввых когда я передвигаю точки (чтобы кривая оставалась связной). И здесь у меня возникли сложности. Сложность в том, что я не знаю, как обратиться к элементу, который я передвигаю. Например, было бы здорово знать индекс этого элемента в списке. Как я могу это сделать? Если для ответа необходимы фрагменты моего кода — я добавлю его в вопрос. Заранее благодарю за любую помощь!

  • damix → Egor Fomin
  • #
  • 13 июня 2020 г. 20:47

Можно классу, который описывает точку, добавить сигнал, который подавать (emit), когда точка перемещается (переопределить mouseMoveEvent или mouseReleaseEvent). Так вот эти сигналы у каждой из точек (например, при добавлении в QList) привязать к слоту какого-нибудь другого объекта. В этом слоте вызывать методы, которые перерисовывают нужные кривые. Статический метод QObject::sender() вернет указатель на точку, которая послала сигнал, т.е. которую переместили. Только нужно привести тип этого указателя.

  • Egor Fomin → damix
  • #
  • 14 июня 2020 г. 19:56

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

Тогда предмет будет выставлен в ту точку, в которую указано. Проблема в том, что у меня предметы уже выставляются туда, куда нужно, и если использовать тот метод в конструкотре, то предмет будет выставлен совершенно в другое место, хотя метод я вызываю с теми же координатами, что и передаются в конструктор. То есть можно сделать вывод, что я получаю какие-то не те координаты, когда кликаю мышкой. Мне было посоветованно использовать функции mapToScene и mapFromScene, но они не помогли — координаты так же отличаются от координат клика мыши. Если мой вопрос нужно дополнить кодом для большей понятности — скажите, я дополню. Заранее благодарю за ваше время

  • Михаиллл
  • #
  • 20 июля 2020 г. 18:49

Добрый день.
Как можно узнать координату на графической сцене при отпускании клавиши мыши?

HTML5 и drag & drop нескольких объектов

Перетаскиванием объектов на HTML5 никого уже не удивишь, но все же попробую рассказать кое о чем интересном, а именно, как сделать красивое перетаскивание нескольких объектов, используя только HTML5.

На странице есть набор элементов типа А, которые можно по одному или группой перетащить в элемент типа Б. Пользователь должен видеть, перетаскивает он один элемент или несколько. Перетаскивать один элемент просто, достаточно присвоить свойству draggable значение true , наверняка, все это делали.

У меня уже готова страница с перетаскиванием «по-одному». Элементы с классом item можно выделить и перенести в элемент с классом dropzone (выделяем, кликнув по квадратику).

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

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

По старинке это делается просто — подписываемся на события мыши и таскаем группу элементов за мышью. С приходом HTML5 от части этой рутины можно избавиться, переложив заботу об анимации на плечи браузера. Работать будет так же как и в случае с одним элементом.

Чтобы при перетаскивании нескольких элементов получить «правильную картинку» воспользуемся методом setDragImage объекта e.dataTransfer .

function setDragImage(image, x, y)
image — элемент, изображение которого будет использовано при перетаскивании.
x и y — смещение.

Итак, перед началом перетаскивания, после того как мы установили данные для перетаскивания e.dataTransfer.setData(‘text/html’, html) , нам нужно собрать правильный элемент-картинку для передачи в метод setDragImage . Сперва определим переменные, которые понадобятся для этого:

Используя frame , установим нужный размер и координаты элементу-картинке:

Добавим копии выделенных элементов к $image :

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

Перемещение объекта путем перетаскивания

Эта страница написана не для той версии программного обеспечения, которую вы в настоящее время выбрали.

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

Последнее обновление March 19, 2020 by Tekla User Assistance tekla.documentation@trimble.com

Перемещение объекта путем перетаскивания

Перемещение объекта путем перетаскивания

Чтобы переместить объект путем перетаскивания, выполните следующие действия.

  1. Выберите Инструменты > Параметры > Перетаскивание , чтобы активировать соответствующий режим.
  2. Выберите объекты для перемещения.
  3. Выполните одно из следующих действий.

Чтобы переместить объекты, перетащите объекты в новое место, удерживая нажатой кнопку мыши.

Чтобы переместить конец объекта, выберите ручку и, удерживая нажатой кнопку мыши, перетащите ручку в новое место.

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

Чтобы включить режим Интеллектуальный выбор , выберите Инструменты > Параметры > Интеллектуальный выбор .

Чтобы переместить метки сетки на чертеже, сначала выберите метку сетки, а затем либо активируйте переключатель выбора Выбрать линию сетки , либо выберите ручку метки сетки.

Перетаскивание (Drag and Drop)

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

Этот документ описывает основной механизм перетаскивания и намечает в общих чертах подход используемый для его включения в пользовательских виджетах. Операции перетаскивания также поддерживаются представлениями элементов Qt и каркасом графического представления. Дополнительная информация доступна в документах Использование перетаскивания (Drag and Drop) и Каркас графического представления.

Классы перетаскивания

Эти классы имеют дело с перетаскиванием и необходимым кодированием и декодированием mime-типов.

Событие, которое посылается виджету, когда операция перетаскивания (drag and drop) входит в его область

Событие, которое посылается виджету, когда операция перетаскивания (drag and drop) покидает его область

Событие, которое посылается виджету в процессе выполнения операции перетаскивания (drag and drop)

Событие, посылаемое при завершении операции перетаскивания (drag and drop)

Преобразует между MIME-типом и форматом унифицированного идентификатора типа (Uniform Type Identifier, UTI)

Отображает открытый стандарт MIME в форматы буфера обмена Windows

Конфигурирование

Объект QApplication предоставляет некоторые свойства, которые относятся к операциям перетаскивания:

  • QApplication::startDragTime описывает количество времени в миллисекундах, которое пользователь должен удерживать нажатой кнопку мыши над объектом до начала операции перетаскивания.
  • QApplication::startDragDistance показывает как далеко пользователь переместил мышь пока удерживал нажатой кнопку мыши до того, как перемещение было интерпретировано как перетаскивание. Используйте большие значения для этих параметров предотвращает случайное перетаскивание когда пользователь только щелкнул по объекту.

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

Перетаскивание

Чтобы начать перетаскивание создайте объект QDrag и вызовите его функцию exec(). В большинстве приложений хорошей идеей начать операцюи перетаскивания только после нажатия кнопки мыши и курсор был перемещён на определённое растояние. Тем не менее, самый простой способ разрешить перетаскивание из виджета — переопределить функцию mousePressEvent() виджета и начать операцию перетаскивания:

Хотя пользователь может получить некоторое время для завершения операции перетаскивания, поскольку приложение связано с функцией exec() являющейся блокирующей функцией, которое возвращает одно из нескольких значений. Это показывает как завершается операция, и ниже описано более подробно.

Обратите внимание на то, что функция exec() не блокирует основной цикл обработки событий.

Для виджетов, которым нужно различать щелчки мыши и перетаскивание, полезно переопределить функцию виджета mousePressEvent() чтобы записать начальную позицию перетаскивания:

Позднее, в mouseMoveEvent(), мы можем определить началось ли перетаскивание, а также сконструировать объект перетаскивания для обработки операции:

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

Отпускание

Чтобы быть способным получить информацию отпущенную на виджет вызовите setAcceptDrops(true) для виджета и переопределите функции-обработчики событий dragEnterEvent() и dropEvent().

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

Функция dragEnterEvent() обычно используется для информирования Qt о типах данных, которые принимает виджет. Вы должны переопределить эту функцию если вы хотите принять QDragMoveEvent или QDropEvent в ваши повторно реализованные dragMoveEvent() и dropEvent().

Следующий код показывает, как можно переопределить dragEnterEvent() чтобы сообщить системе перетаскивания, что мы обрабатываем только простой текст:

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

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

В данном случае, мы принимаем предлагаемое действие без его проверки. В реальных приложениях, может быть необходимо возвратить из функции dropEvent() без приёма предлагаемого действия или обработки данных, если действие не является соответствующим. Например, мы можем выбрать игнорирование действий Qt::LinkAction если мы не поддерживаем ссылки на внешние источники в нашем приложении.

Перегрузка предлагаемых действий

Мы также можем игнорировать предлагаемое действие, и выполнить некоторое действие на данных. Что сделать это, мы будем вызывать событие объекта setDropAction() с предпочтительным действием из Qt::DropAction перед вызовом accept(). Это гарантирует, что замена действия отпускания используется вместо предлагаемого действия.

Для более сложных приложений переопределение dragMoveEvent() и dragLeaveEvent() позволит вам сделать некоторые части ваших виджетов чувствительными к событиям отпускания, и даст вам больше контроля над перетаскиванием в вашем приложении.

Создание подклассов сложных виджетов

Некоторые стандартные виджеты Qt предоставляют свою собственную поддержку перетаскивания. При создании подклассов этих виджетов, возможно необходимо будет переопределить dragMoveEvent() в дополнение к dragEnterEvent() и dropEvent() чтобы предохранить базовый класс от предоставления обработки перетаскивания по умолчанию, и для обработки любых особых случаев интересных вам.

Действия перестаскивания (Drag and Drop)

В простейшем случае цель действия перетаскивания получает копию перетаскиваемых данных, а источник решает удалить ли оригинал. Это описывается действием CopyAction. Цель может также выбрать обработку других действий, особенно действия MoveAction LinkAction. Если источник вызывает QDrag::exec() и она возвращает MoveAction, то источник отвечает за удаление любых оригинальных данных если он выбран это делать. Объекты QMimeData и QDrag созданы виджетом источника не будут удалены — их разрушит Qt. Цель отвечает за получение владения над данными, отправленными в операцию перетаскивания; обычно это делают сохраняя ссылки на данные.

Если цель понимает действие LinkAction, она будет хранить собственную ссылку на оригинальную информацию; источнику не нужно выполнять какую-либо дополнительную обработку данных. Наиболее общее использование действий перетаскивания — когда выполняется перемещение внутри одного и того же виджета; для получения дополнительной информации об этой возможности смотрите раздел Действия отпускания.

Другой значительное использование действий перетаскивания — когда использование типа ссылки, например, text/uri-list, где перетаскиваемые данные действительно ссылаются на файлы или объекты.

Добавление новых типов перетаскивания

Перетаскивание не ограничено текстом и изображениями. Любой тип информации может быть передан в операцию перетаскивания. Чтобы перетащить информацию между приложениями, приложение должно быть способно указать для всех других данные в каких форматах каждого они могут принять и в каком они могут произвести. Это достигается используя MIME-типов. Объект QDrag, созданный источником, содержит список MIME-типов, которые он использует для представления данных (упорядоченный от наиболее соответствующих к наименее соответствующим), а цель отпускания использует один из них для доступа к данным. Для обычных типов данных вспомогательные функции обрабатывают MIME-типы, используемые прозрачно, однако для пользовательских типов данных необходимо заявлять их явно.

Чтобы реализовать действия перетаскивания для типа информации, который не охватывается вспомогательными функциями QDrag, первый и наиболее важный шаг — взглянуть на существующие форматы, которые являются соответствующими: Internet Assigned Numbers Authority (IANA) предоставляет иерархический список медийных MIME-типов в Information Sciences Institute (ISI). Используя стандартные MIME-типы максимизируют совместимость вашего приложения с другим программным обеспечением сейчас и в будущем.

Для поддержки дополнительного медийного типа просто установите данные в объект QMimeData с помощью функции setData(), предоставляющей полный MIME-тип и QByteArray, содержащий данные в соответствующем формате. Следующий код получает растровое изображение из метки и сохраняет его как файл Portable Network Graphics (PNG) в объекте QMimeData:

Конечно, для этого случая мы можем просто использовать setImageData() вместо предоставленных данных изображения в различных форматах:

Подход QByteArray по-прежнему полезен в этом случае, поскольку он предоставляет больший контроль над количеством данных сохраняемых в объекте QMimeData.

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

Действия отпускания

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

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

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

Принятые действия отпускания можно отфильтровать в функции виджета dragMoveEvent(). Тем не менее, возможно принять все предлагаемые действия в dragEnterEvent() и позволить пользователю решить, какие из них принять позднее:

Когда отпускание произойдёт в виджете, вызывается функция-обработчик dropEvent(), и мы можем рассмотреть каждое возможное действие по очереди. Сначала мы распределить операции перетаскивания внутри одного и того же виджета:

В этом случае мы отказались рассматривать операции перемещения. Каждый тип действия отпускания, который мы приняли, проверяется и рассматривался соответственно:

Обратите внимание на то, что мы проверяли отдельные действия отпускания в вышеприведённом коде. Как было сказано выше в разделе Перегрузка предлагаемых действий, иногда необходимо перегрузить предлгаемое действие отпускания и выбрать другое из выборки возможных действия отпускания. Чтобы это сделать вам нужно проверить наличие каждого действия в значении функции события possibleActions(), установить действие отпускания с помощью setDropAction() и вызвать accept().

Прямоугольники отпускания

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

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

Буфер обмена

Приложения также могут обмениваться информацией друг с другом помещая данные в буфер обмена. Чтобы получить к нему доступ вам нужно получить объект QClipboard из объекта QApplication:

Класс QMimeData используется для представления данных, которые перемещаются в и из буфера обмена. Чтобы поместить данные в буфер обмена вы можете использовать вспомогательные функции setText(), setImage() и setPixmap() для обычных типов данных. Эти функции аналогичны таким же находящимся в классе QMimeData, за исключением того, что они также получают дополнительный аргумент, который управляет сохранением данных: Если задан Clipboard, то данные помещаются в буфер обмена; если задан Selection , то данные помещаются в выделение мыши (только в X11). По умолчанию, данные помещаются в буфер обмена.

Например, мы можем скопировать содержимое QLineEdit в буфер обмена с помощью следующего кода:

Данные с разными MIME-типами также могут быть помещены в буфер обмена. Создайте объект QMimeData и установите данные с помощью функции setData() способом, описанным в предыдущем разделе; этот объект затем можно поместить в буфер обмена с помощью функции setMimeData().

Класс QClipboard может уведомлять приложение об изменении содержащихся в нём данных посредством своего сигнала dataChanged(). Например, мы можем отслеживать буфер обмена присоединив этот сигнал к слоту в виджете:

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

Сигнал selectionChanged() может быть использован в X11 для отслеживания выделения мыши.

Примеры

Взаимодействие с другими приложениями

В X11 используется открытый протокол XDND, в то время как в Windows Qt использует стандарт OLE, а Qt для Mac OS X использует Carbon Drag Manager. В X11 XDND использует MIME, поэтому никакого преобразования не нужно. Qt API не зависит от платформы. В Windows, MIME-ориентированные приложения могут общаться используя имена буфера обмена, которые являются MIME-типам. Уже несколько приложений Windows используют соглашения именования MIME для своих форматов буфера обмена. Внутри Qt использует QWindowsMime и QMacPasteboardMime для преобразования закрытых форматов буфера обмена в и из MIME-типов.

В X11 Qt также поддерживает отпускание посредством Протокола перетаскивания Motif. Реализация объединяет некоторый код, который был первоначально написан Далиелем Дардайллером (Daniel Dardailler), и адаптирован для Qt Мэттом Коссом (Matt Koss) и Nokia. Вот оригинальное уведомление об авторских правах:

Copyright 1996 Daniel Dardailler. Copyright 1999 Matt Koss

Permission to use, copy, modify, distribute, and sell this software for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Daniel Dardailler not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. Daniel Dardailler makes no representations about the suitability of this software for any purpose. It is provided «as is» without express or implied warranty.

Note: The Motif Drag & Drop Protocol only allows receivers to request data in response to a QDropEvent. If you attempt to request data in response to e.g. a QDragMoveEvent, an empty QByteArray is returned.

Все остальные торговые марки являются собственностью их владельцев. Политика конфиденциальности

Лицензиаты, имеющие действительные коммерческие лицензии Qt, могут использовать этот документ в соответствии с соглашениями коммерческой лицензии Qt, поставляемой с программным обеспечением, либо, альтернативно, в соответствии с условиями, содержащимися в письменном соглашении между вами и Nokia.

Кроме того, этот документ может быть использован в соответствии с условиями GNU Free Documentation License version 1.3, опубликованной фондом Free Software Foundation.

Перетаскивание объектов

Свойства DragMode, DragCursor, методы BeginDrag, OnDragOver, OnDragDrop, OnEndDrag, OnStartDrag, параметр Accept

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

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

Начало перетаскивания определяется свойством DragMode, которое может устанавливаться в процессе проектирования или программно равным dmManual или dmAutomatic. Значение dmAutomatic (автоматическое) определяет автоматическое начало процесса перетаскивания при нажатии пользователем кнопки мыши над компонентом. Однако в этом случае событие OnMouseDown, связанное с нажатием пользователем кнопки мыши, для этого компонента вообще не наступает.

Значение dmManual (ручное) говорит о том, что начало процесса перетаскивания должен определить программист. Для этого он должен в соответствующий момент вызвать метод BeginDrag. Например, он может поместить вызов этой функции в обработчик события OnMouseDown, наступающего в момент нажатия кнопки мыши. В этом обработчике он может проверить предварительно какие-то условия (режим работы приложения, нажатие тех или иных кнопок мыши и вспомогательнх клавиш) и при выполнении этих условий вызвать BeginDrag.

Пусть. например, процесс перетаскавания должен начаться, если пользователь нажал левую кнопку мыши и клавишу Alt над списком ListBox1. Тогда свойство DragMode этого компонента надо установить в dmManual, а его обработчик события OnMouseDown может иметь вид:

Параметр Button обработчика события OnMouseDown показывает, какая кнопка мыши была нажата, а параметр Shift является множеством, содержащим обозначения нажатых в этот момент кнопок мыши и вспомогательных клавиш клавиатуры. Если нажата левая кнопка мыши и клавиша Alt, то вызывается метод BeginDrag данного компонента.

В функцию BeginDrag передано значение False. Это означает, чтопроцесс перетаскивания начнется не сразу. а только после того, как пользователь сдвинет мышь с нажатой при этом кнопкой. Это позволяет отличить простой щелчок мыши от начала перетаскивания. Если же передать в BeginDrag значение True, то перетаскивание начнется немедленно.

Когда начался процесс перетаскивания, обычный вид курсора изменяется. Пока он перемещается над формой или компонентами, которые не могут принять информацию, он обычно имеет вид crNoDrop. Если же он перемещается над компонентом, готовым принять информацию из перетаскиваемого объекта, то приобретает вид, определяемый свойством перетаскиваемого объекта DragCursor. По умолчанию это свойство равно crDrag, что соответствует изображению. Вид курсора определяется свойством DragCursor перетаскиваемого объекта, а не того объекта, над которым перемещается курсор.

В процессе перетаскивания компоненты, над которыми перемещаетяс курсор, могут информировать о готовности принятьинформацию от перетаскиваемого объекта. Для этого в компоненте должен быть предусмотрен обработчик события OnDragOver, наступающего при перемещении над данным компонентом курсора, перетаскивающего некоторый объект. В этом обработчике надо проверить, может ли данный компонент принять информацию перетаскиваемого объекта, и, если не может, задать значение False передаваемому в обработчик параметру Accept. По умолчанию этот параметр равен True, что означает возможность принять перетаскиваемый объект. Обработчик для списка может иметь, например, следующий вид:

В нем сначала проверяется, не является ли данный компонент (Sender) и перетаскиваемый объект (Source) одним и тем же объектом. Это сделано, чтобы избежать перетаскивания информации внутри одного и того же списка.

Значение параметра Accept, задаваемое в обрапботчике события onDragOver, определяет вид курсора, перемещающегося при перетаскивании над данным компонентом. Этот вид показывает пользователю, может ли данный компонент принять перетаскиваемую информацию. Если в компоненте не описан обработчик события onDragOver, то считается, что данный компонент, не может принять информацию перетаскиваемого объекта.

Процедура приема информации от перетаскиваемого объекта записывается в обработчике события OnDragDrop принимающего компонента. Это событие наступает, если после перетаскивания пользовательотпустил клавишу мыши над данным компонентом. В обработчик этого события передаются параметры Source (объект-источник) и X и Y координаты курсора. Если продолжить пример перетаскивания информации из одного списка в другой, то обработчик события OnDragDrop может иметь вид:

В этом обработчике сторка, выделенная в списке-источнике (Source as TListBox).Items[(Source as TListBox).ItemIndex]. добавляется в список-приемник методом (Sender as TListBox).Items.Add. Используется операция AS, позволяющая расссматривать параметры Sender и Source как указатели на объект класса TListBox. Это делается потому, что эти параметры объявлен в заголовке процедуры как указатели на объекты класса TObject. Но в классе TObject нет свойств Items и ItemIndex, которые нам требуются. Эти свойства определены в классе TListBox, являющемся наследником TObject. Поэтому с параметрами Sender и Source в данном случае надо оперировать как с указателями на объекты TListBox, что и выполняет операция as.

В данном случае можно было бы не использовать параметр Sender, заменив (Sender as TListBox) просто на ListBox1. Но запись оператора в общем виде с помощью параметра Sender позволяет воспользоваться таким обработчиком и для других компонентов ListBox, если они имеются в приложении.

После завершения или прерывания перетаскивания наступает событие OnEndDrag, в обработчике которого можно предусмотреть какое-то дополнительное действие. Имеется также связанное с перетаскиванием событие OnStartDrag, которое позволяет произвести какие-то операции в начале перетаскивания, когда иным способом этот момент нельзя зафиксировать.

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

  • Написать для одного списка обработчик события onDragOver. Для всех остальных списков сослаться в событиях onDragOver на этот же обработчик (выделив в форме все оставшиеся списки).
  • Написать аналогичным образом для всех списков обработчик события OnDragDrop.

Если начинать перетаскивание нужно только при выполнении какого-то дополнительног условия, например, при нажатии клавиши Alt, то потребуется:

  • Задать для всех списков значение свойства DragMode, равное dmManual и написать обработчик события OnMouseDown.

В приведенном ниже примере:

  • многострочный редактор Memo1 готов принять информацию от TLabel и TListBox;
  • списки ListBox готовы принять информацию от всех других списков и при этом, если информация передается не от списка ListBox2, то их списка-источника она удаляется (переносится). Из списка ListBox2 информация только копируется.
  • для метки Label1 c заголовком dmAutomatic определено событие OnEndDrag так, что выводится сообщение об успешном или неуспешном завершении процесса переноса, которое выводится в случае включения флажка с заголовком .
  • для списков ListBox3 и ListBox4 перетаскивание возможно только при нажатой клавише Alt, но для ListBox4 перетаскивание начинается сразу (значение функции BeginDrag(true)), а для ListBox3 (и метки Label1) момент перетаскивания определяется началом движения мышки (значение функции BeginDrag(false)).
Илон Маск рекомендует:  Слой с одним отрезанным уголком
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL