crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

2 страниц V   1 2 >  
Ответить в данную темуНачать новую тему
> Drag&drop
borune
  опции профиля:
сообщение 8.1.2011, 12:18
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 152
Регистрация: 1.1.2011
Пользователь №: 2314

Спасибо сказали: 0 раз(а)




Репутация:   0  


Ребят, помогите плиз разобраться с реализацией данного механизма средствами qt.

Из прочтения ассистанса я мало что понял. Там написано, что базовым классом для реализаций механизма drag&drop является класс QDrag. Перетаскиваемые данные надо положить в объект класса QMimeData. Также предлагается перезагрузить функции нажатия и отпускания кнопок мыши.

Написано все складно, да вот я, например, ничего не понял.

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

Области, куда можно помещать виджет, я думаю, удобно реализовать с помощью класса QFrame, поскольку эти области представляют собой части экрана, образованные параллельными горизонтальными линиями. А вот как сделать все остальное, а именно активировать механизм перетаскивания, сделать так, чтобы если пользователь отпускает виджет в той области, в которой этот виджет располагаться не может, то данный виджет "ехал" бы в исходное положение, а также разделить обработку левого клика при перетаскивании и простого левого клика (если я правильно понял, это делается при помощи QApplication::startDragTime(int)), я бы хотел спросить у вас.

Заранее всем спасибо)

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

примерчик


#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDrag>
#include <QMimeData>
#include <QMouseEvent>
#include "D:/qt/tree/QFoto.h"

QFoto *tt;

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{

tt = new QFoto(QString(""),this,Qt::Widget,20,20,QPixmap(tr("D:\\gnines.gif")),QColor(0,0,0));
connect(tt,SIGNAL(LeftPressed(QMouseEvent*)),this,SLOT(mousePressEvent(QMouseEve
nt*)));
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton
&& tt->geometry().contains(event->pos())) {

QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;

mimeData->setText(tr("lala"));
drag->setMimeData(mimeData);
drag->setPixmap(QPixmap(tr("D:\\tt.gif")));

Qt::DropAction dropAction = drag->exec();

}
}


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

Сообщение отредактировал borune - 8.1.2011, 12:42
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 8.1.2011, 12:31
Сообщение #2


фрилансер
******

Группа: Участник
Сообщений: 2939
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


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

Сообщение отредактировал Алексей1153 - 8.1.2011, 12:31
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
borune
  опции профиля:
сообщение 8.1.2011, 13:25
Сообщение #3


Участник
**

Группа: Участник
Сообщений: 152
Регистрация: 1.1.2011
Пользователь №: 2314

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата(Алексей1153 @ 8.1.2011, 12:31) *
если всё происодит в пределах родительского виджета, то никаких наворотов не нужно - достаточно отловить нажатие левой кнопки, затем запомнить начальные координаты и при движении мыши двигать перетаскиваемое дитя за курсором. По отпусканию кнопки сохранить новое положение (да оно уже и так сохранено)


я нашел пример кутэшный вот этот. там все описано и, главное, все работает. Правда мало что понятно)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 8.1.2011, 13:59
Сообщение #4


фрилансер
******

Группа: Участник
Сообщений: 2939
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


borune, это случай перетаскивания с виджета на виджет. А в пределах одного виджета всё попроще

PS очепятка
Цитата
где используется перетаскивание, the пользователь начинает

:)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 8.1.2011, 14:06
Сообщение #5


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(borune @ 8.1.2011, 15:25) *
Правда мало что понятно
а что именно не понятно в примере?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
borune
  опции профиля:
сообщение 8.1.2011, 15:03
Сообщение #6


Участник
**

Группа: Участник
Сообщений: 152
Регистрация: 1.1.2011
Пользователь №: 2314

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата(Алексей1153 @ 8.1.2011, 13:59) *
borune, это случай перетаскивания с виджета на виджет. А в пределах одного виджета всё попроще

PS очепятка
Цитата
где используется перетаскивание, the пользователь начинает

:)


Алексей1153 но ведь мне наверное придется создавать в окне QFrame'ы для того, чтобы обеспечить только разрешенные положения перемещаемых виджетов..

Кстати вот как раз насчет этого..вот с того же сайта цитата

цитата

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

void Window::dragMoveEvent(QDragMoveEvent *event)
{
if (event->mimeData()->hasFormat("text/plain")
&& event->answerRect().intersects(dropFrame->geometry()))

event->acceptProposedAction();
}

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


В соответствии с этим я сделал такую функцию:
моя функция
void MainWindow::dragMoveEvent(QDragMoveEvent *event)
{
if ((event->mimeData()->hasFormat("application/x-dnditemdata"))
&& (frame->geometry().contains(event->answerRect()))){

event->acceptProposedAction();
frame->setVisible(true);
}
else event->ignore();
}

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

То есть event->answerRect().intersects(dropFrame->geometry()) примет значение bool в случае, если хотя бы один пиксел "текущего" положения виджета находится внутри dropFrame. Вот я создал этот фрейм, занимающий верхнюю половину окна, сделал его невидимым. При начале перетаскивании виджета фрейм появляется, чтобы обозначить разрешенные границы переноса. Также вместо условия в примере я использую, на мой взгляд, более строгое - frame->geometry().contains(event->answerRect()).

Что я наблюдаю. Зажимаю левую кнопку и начинаю тащить лейбл по направлению к нижней границе фрейма. Как только курсор (а именно, самый верхний пиксел стрелки) выходит за рамки фрейма, курсор меняет форму на перечеркнутую окружность. Из этого можно сделать вывод о том, что конец курсора указывает на нижнюю границу перетаскиваемого виджета. Если я правильно понял, то это устанавливается так: drag->setHotSpot(event->pos() - child->pos());

Я пробовал написать так: drag->setHotSpot(QPoint(pixmap.width()/2,pixmap.height()/2));

но это ничего не изменило. Значит дело не в этой строке...

Далее. Если я, например, схвачу виджет за самый верхний край, то смогу его вытащить за пределы фрейма почти полностью. Это тоже понятно, поскольку курсор за пределы фрейма при этом не выходит. А вот далее начинаются необъяснимые для меня вещи. Я постарался показать их на скриншотах.

1.
2.
3.

Даже после этапа 3 я могу перетаскивать виджет (!!!). Тут уж никак не может выполняться условие нахождения виджета в пределах фрейма. Правда виджет перетаскивается не так, как в пределах фрейма - я могу его перетаскивать только пока курсор мыши находится в пределах прямоугольника, соответствующего положению виджета до начала этого перетаскивания.

Объясните пожалуйста, как такое вообще может быть?

Сообщение отредактировал borune - 8.1.2011, 15:30
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 8.1.2011, 16:53
Сообщение #7


фрилансер
******

Группа: Участник
Сообщений: 2939
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


borune, ты суть улови:

1) для перемещения внутри одного родителя достаточно сообщений мыши - нажатие, перемещение, отпускание.
2) для перемещения между двумя всё меняется: событие нажатия кнопки используется для запуска алгоритма, который использует методы

void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);

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

разберись с логикой методов, почитай их описание в справке - и поймёшь, как это всё для любых виджетов использовать
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
borune
  опции профиля:
сообщение 8.1.2011, 18:28
Сообщение #8


Участник
**

Группа: Участник
Сообщений: 152
Регистрация: 1.1.2011
Пользователь №: 2314

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата(Алексей1153 @ 8.1.2011, 16:53) *
borune, ты суть улови:

1) для перемещения внутри одного родителя достаточно сообщений мыши - нажатие, перемещение, отпускание.


То есть если у меня один виджет, то QDrag использовать не обязательно, можно использовать три сигнала от мыши - MousePressEvent, mouseMoveEvent mouseReleaseEvent?

Сообщение отредактировал borune - 8.1.2011, 18:33
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 8.1.2011, 18:36
Сообщение #9


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Алексей1153 @ 8.1.2011, 18:53) *
1) для перемещения внутри одного родителя достаточно сообщений мыши - нажатие, перемещение, отпускание.
если родитель с компоновщиком, то перетаскивать ничего не получится отлавливая нажатия мыши, т.к. компоновщик управляет положением виджета
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
borune
  опции профиля:
сообщение 8.1.2011, 18:44
Сообщение #10


Участник
**

Группа: Участник
Сообщений: 152
Регистрация: 1.1.2011
Пользователь №: 2314

Спасибо сказали: 0 раз(а)




Репутация:   0  


не..никакого компоновщика нету..

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

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

и еще..как в таком случае отличить левый клик от перетаскивания?

Сообщение отредактировал borune - 8.1.2011, 21:00
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 19.4.2024, 14:58