Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Drag&Drop между разными CTreeView видами 
V
    Опции темы
voov
Дата 17.7.2008, 18:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



У меня есть 2 вида унаследованые от CTreeView. Нужно итем из дерева одного вида перетянуть на итем дерева другого вида.

Перетаскивание итема в дереве одного вида сделал по статье МСДН Dragging a Tree-View Item. 
В OnTvnBegindrag вида делаю 
Код

    CImageList* pImageList = GetTreeCtrl().CreateDragImage(pNMTreeView->itemNew.hItem);
    pImageList->BeginDrag(0, CPoint(0, 0));
    pImageList->DragEnter(this, pNMTreeView->ptDrag);

А в OnMouseMove 
Код

    CImageList::DragMove(point);

Вместе с курсором двигается картинка сделаная по итему дерева. Но при выходе курсора за пределы окна вида картинка исчезает.

Как сделать, чтобы картинка не исчезала?
PM MAIL   Вверх
Earnest
Дата 18.7.2008, 10:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Можно попробовать в DragEnter другое окно передать (общего родителя или главное окно). Это именно оно все блокирует...


--------------------
...
PM   Вверх
voov
Дата 18.7.2008, 10:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



Да, получилось. Earnest, спасибо.
Верно говорят, что утро вечера мудренее. Вчера был в полном тупике, а сегодня и сам уже начал двигаться в этом направлении.
В OnTvnBegindrag владельцем картинки сделал фрейм. Ниже код.
Кстати, может есть способ попроще добраться до родительского фрейма? У меня в фрейме 2 сплиттера, потому приходится вызывать GetParent 3 раза.
Код

    CWnd* frame = this->GetParent()->GetParent()->GetParent();
    ((CChildFrame*)frame)->SetCapture();

    pImageList->BeginDrag(0, CPoint(0, 0));
    pImageList->DragEnter(frame, pNMTreeView->ptDrag);

Нужно было еще DragMove делать
Код

CImageList::DragMove(point);
 в OnMouseMove фрейма, а не вида.

PM MAIL   Вверх
Earnest
Дата 18.7.2008, 11:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



GetParentFrame попробуй


--------------------
...
PM   Вверх
voov
Дата 18.7.2008, 11:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



Цитата(Earnest @  18.7.2008,  11:35 Найти цитируемый пост)
GetParentFrame попробуй 

точно, спасибо.

Еще один момент. Теперь картинка появляется чуть выше чем нужно. Нужно в BeginDrag задать смещение вместо нулевой точки:

pImageList->BeginDrag(0, CPoint(0, 0));

но никак не могу получить это смещение...
PM MAIL   Вверх
Earnest
Дата 18.7.2008, 12:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Хм... у меня были проблемы с горизонтальным смещением... я делала так (кусок обработчика BEGINDRAG):
  
Код

 m_hDragItem = nmtv.itemNew.hItem;
   CPoint pt = nmtv.ptDrag;

   CRect rc;
   m_tvOwner.GetItemRect (m_hDragItem, rc, true);

   m_pDragImage = m_tvOwner.CreateDragImage (m_hDragItem);
   m_pDragImage->BeginDrag (0, CPoint (pt.x - rc.left, 0));
   m_pDragImage->DragEnter (&m_tvOwner, pt);

А вертикальное если и есть - то незаметное: пока как следует не отъедет мышь, картинка сливается

Добавлено через 2 минуты и 21 секунду
Кстати, если во время mousemove ты помечаешь dropTarget в дереве, не забудь обернуть это в DragLeave\DragEnter, иначе грязь будет


--------------------
...
PM   Вверх
voov
Дата 18.7.2008, 14:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



Решил проблему со смещением smile. Это было смещение верхнего левого угла онка фрейма относительно верхнего левого угла окна вида. Код вот такой.
Код

    CWnd* frame = GetParentFrame();
    frame->GetWindowRect(&rect);
    ScreenToClient(&rect);
    pImageList->BeginDrag(0, CPoint(rect.left, rect.top));
    pImageList->DragEnter(frame, pNMTreeView->ptDrag);

Теперь картинка появляется в том же месте, что и раньше (когда владельцем картинки был сам вид)
Код

    pImageList->BeginDrag(0, CPoint(0, 0));
    pImageList->DragEnter(this, pNMTreeView->ptDrag);

PM MAIL   Вверх
voov
Дата 18.7.2008, 14:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



Цитата(Earnest @  18.7.2008,  12:03 Найти цитируемый пост)
Кстати, если во время mousemove ты помечаешь dropTarget в дереве, не забудь обернуть это в DragLeave\DragEnter, иначе грязь будет 

Не совсем понял. 
В mousemove я делаю GetTreeCtrl().SelectDropTarget(hItem) чтобы пометить итем как цель.
Какая грязь будет? Можно поподробнее про эти  DragLeave\DragEnter (есть еще OnDragOver и OnDrop). Где и зачем нужно их использовать и что в них должно быть?

Сейчас начинаю операцию перетаскивания по событию TVN_BEGINDRAG в виде, слежу за мышью в OnMouseMove родительского фрейма, а заканчиваю операцию по WM_LBUTTONUP в том же фрейме. Может нужно как-то иначе?
PM MAIL   Вверх
Earnest
Дата 21.7.2008, 09:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Цитата(voov @  18.7.2008,  15:54 Найти цитируемый пост)
В mousemove я делаю GetTreeCtrl().SelectDropTarget(hItem) чтобы пометить итем как цель.

Я тоже. И если не делаю DragLeave\DragEnter - то возникает грязь: либо недорисованне выделение, либо лишнее... Не всегда, но бывает. Перед SelectDropTarget вызываешь DragLeave, а после DragEnter.

Цитата(voov @  18.7.2008,  15:54 Найти цитируемый пост)
Сейчас начинаю операцию перетаскивания по событию TVN_BEGINDRAG в виде, слежу за мышью в OnMouseMove родительского фрейма, а заканчиваю операцию по WM_LBUTTONUP в том же фрейме. Может нужно как-то иначе? 

Все правильно. Только почему во фрейме-то MOUSEMOVE и LBUTTONUP... впрочем, если так удобнее, то дело твое. 
Я предпочитаю все делать в одном месте. А всю информацию о перетаскивании засунуть в отдельный класс, типа CDragInfo, чтобы не мусорить в классе-дереве, у которого есть и другие нагрузки.
А, поняла - ты же между разными видами таскаешь. Только если виды одного типа, я бы все равно фрейм грузить не стала. Одно дело - использовать ссылку на него в DragEnter, а другое - засовывать ненужную ему функциональность. Ты же capture ставишь на дерево - так что маус-мув по-любому получишь.



--------------------
...
PM   Вверх
voov
Дата 21.7.2008, 09:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



Код

    ((CChildFrame*)frame)->SetCapture();

Capture я ставлю на фрейм. И перетаскивание нужно делать между разными видами. Виды разных типов, к тому же нужно будет таскать и на вид без дерева (потом).
В фрейме 2 обработчика MOUSEMOVE и LBUTTONUP, которые выполняют необходимые действия по перетаскиванию картинки, по координатам курсора определяют над каким видом мышь и переадресуют дальнейшую обработку в соответствующий вид.

Цитата(Earnest @  21.7.2008,  09:11 Найти цитируемый пост)
И если не делаю DragLeave\DragEnter - то возникает грязь: либо недорисованне выделение, либо лишнее... 

Так ты о методах CImageList. А я то думал о переопределенных методах вида (OnDragLeave, OnDragOver  ...). Чтобы нормально отрисовывались выделеные итемы дерева я использую DragShowNolock(). Примерно так
Код

    CImageList::DragShowNolock(false);
    GetTreeCtrl().SelectDropTarget(hTarget);
    CImageList::DragShowNolock(true);

PM MAIL   Вверх
Earnest
Дата 21.7.2008, 15:32 (ссылка) |  (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Да, действительно, DragShowNoLock, возможно, даже лучше...

Насчет идеологии: представь, что таскать нужно между видами разных фреймов - кто тогда обрабатывать должен?
Есть, конечно, возможность прорубиться через OLE Drag & Drop, но мне там активно не понравилось... Если речь идет о своем приложении, где ты царь и бог, проще ручками, как мы и делаем.
Я, при перетаскивании между разными окнами (вообще не связанными, но в моем приложении) делала так:
1) определяем структуру CDragInfo, куда помещаем ссылку на окно-владельца (кто начал drag & drop), итем, указатель (или hWnd) окна, куда будем кидать (это определяется во время таскания), таймер (для авто-скроллинга во время таскания) и т.д. - все, что может понадобиться для задачи - скажем, тип таскаемого элемента, etc
В этот класс переношу весь код, нужный для реализации (установку capture, выбор цели и прочая) 
2) определяю указатель на этот объект во всех классах, которые могут начать перетаскивание своих элементов
3) определяю несколько сообщений: TVM_DRAGENTER, TVM_DRAGLEAVE, TVM_DROPITEM - чтобы минимизировать обмен между разными окнами и их знание друг о друге.
4) На BeginDrag окно-владелец создает объект dragInfo, на mouseMove, lbuttonup и по Escape вызывает соответствующие функции объекта (в 2 последних случаях - потом разрушает его).
5) В процессе обработки mouseMove объект dragInfo посылает окну, над которым находится курсор, сообщение DRAGENTER - типа, хочешь, тебе чего-нибудь кинут? Если оно отвечает "хочу" - это будет новая цель, а старой, если она была, посылают DRAGLEAVE (чтобы она сняла выделение droptarget). DROPITEM посылается при завершении перетаскивания.
Таким образом, окна друг о друге могут ничего не знать, вся коммуникация идет через windows-сообщения + структура данных.
Вся функциональность (почти) - в классе DragInfo, окна-владельцы только вызывают в нужные моменты соответствующие функции + выделяют у себя цель + реализую вставку (и\или удаление).
Фактически, примерно так же работает OLE Drag & Drop, только там все гораздо тяжелее и накрученнее...


--------------------
...
PM   Вверх
voov
Дата 21.7.2008, 16:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Патамушта мы пилоты
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 29.11.2007

Репутация: 8
Всего: 8



Чтож, спасибо за информацию. Приму к сведению. 
Для текущей задачи достаточно того, что уже есть. К тому же, не хочу переписывать уже рабочий код. Но в будущем пригодится.  smile 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.0585 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.