| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Visual C++/MFC/WTL > drag и drop елементов управления |
| Автор: OverBug 21.11.2006, 10:51 |
| Здрасти.... Пытался найти подобную тему в истории тем.... не нашел... вернее нашел драг ГДИ объектов.... но это нето... я пытаюсь своими силами склепать нестандартные элементы управления... делаю их из набора объектов CWnd... эти окна прорисовываются на форме и вот такой вопрос... как их сделать так чтобы можно их таскать по форме... просто перемещать... искал событие OnDrag и др в событиях CWnd.. не нашел... но они есть, как я понял, у CView и дочерних от него классов. и можно ли вообще перемещать объекты CWnd? я посмотрел один примерчик с даргом и там создаются объеты на базе CCmdTarget и создаются они в объекте ScrollView... |
| Автор: OverBug 21.11.2006, 14:15 |
| кажись перевелись спецы по drag&drop..... очередной раз искал и не нашел подобных тем... Уважаемые форумчане!!!!! ктонибудь что нибудь знает по данной тематике.... |
| Автор: Earnest 21.11.2006, 15:58 |
| Есть OLE drag & drop, если желаешь - разбирайся. Смотри классы COleDataSource, COleDropSourse и т.д. Но мне лично кажется, что для реализации в рамках твоей задачи это слишком громоздко. Я бы сделала ручками: на WM_LBUTTONDOWN определяем таскаемый объект, ставим Capture, меняем курсор ..., на WM_MOUSEMOVE перемещаем, на WM_LBUTTONUP - отпускаем. Всего-то делов. |
| Автор: OverBug 21.11.2006, 17:23 |
| Sorry.... what is capture and where он должен быть или есть.... |
| Автор: Earnest 21.11.2006, 17:28 |
| SetCapture, читай MSDN. |
| Автор: Любитель 21.11.2006, 17:44 |
| Енто означает возможность ловли всех перемещений мыхи вне твоего окна. |
| Автор: OverBug 22.11.2006, 10:18 | ||
вообщем я вчера
помоему так... писал по памяти... вообщем когда я начинаю таскать объект то он не идет за курсором мыши а находится гдето между координатой 0,0 парента и положением курсора плюс к этому из этой же координаты идет еще один... т.е. их два... видно два... на самом деле ИМХО координата скачет в два места... пытался преоблазовывать point.x в int... и ни как... я вообще правильно все делаю? |
| Автор: Earnest 22.11.2006, 17:10 |
| Не if (this->GetCapture()), а if (GetCapture() == this). Но лучше поставь флаг в OnLButtonDown. Т.к. Capture может пропасть по независящим от тебя причинам. По этому поводу нужно еще обрабатывать WM_CAPTURECHANGED - примерно так, как сброс драга. А с координатами ты уж сам разбирайся - есть, в конце концов, отладчик и отладочная печать ... Разве что... обрати внимание на то, в какой системе координаты у тебя: дочернее окно хочет получать координаты клиентской области парента (MoveWindow). |
| Автор: OverBug 22.11.2006, 23:52 |
| я так понял что: 1)т.е. такой флаг: nFlags == MK_LBUTTON 2)при обработке "WM_CAPTURECHANGED - примерно так, как сброс драга", т.е. выполнить ReleaseCapture(); я еще забыл сказать что когда перетаскиваемый объект перекрывает другие объекты такого же класса, то они не перерисовываются.... почему такое? может что-то я упустил? |
| Автор: Earnest 23.11.2006, 10:44 |
Нет... введи управляющий флаг в классе, например m_bInDrag. Который будешь устанавливать в true на LButtonDown, если начат драггинг, т.е. ткнули в объект, который можно таскать. И сбрасывай при завершении драггинга. Capture- это всего лишь механизм, причем не только тобой контролируемый, поэтому не стоит использовать его как признак драггинга. Еще заметила... Не надо вызывать OnPaint после MoveWindow. Это такая штука... OnPaint должна вызывать сама система, причем тогда, когда ей удобно... Ты должен вызывать InvalidateRect. Причем у парента и дважды: для старой позиции контрола и для новой. |
| Автор: OverBug 27.11.2006, 10:06 | ||
вообщем... пока получилось следующее (даю исходник с целью критики... и может быть кому исче понадобится)
работа такого кода меня устраивает.... и скоординатами разобрался... когда перетаскиваю окно... то оно само прорисовывается и для этого не надо было вызывать перерисовку самому... сейчас бьюсь над тем чтобы окно понимало что на него перетаскивают что-то..... |
| Автор: Earnest 27.11.2006, 15:06 | ||
| OverBug, ты читаешь через строку: здесь вижу, здесь нет. Еще раз повторяю: код не правильный, т.к. GetCapture возвращает окно, которое захватило мышь. Ведь захватить мышь может не только твое окно. Если уж проверяешь Capture то сравнивай с this. И не используй Capture как признак драггинга, неужели флажок трудно ввести? Твой код работает только в исключительно благоприятных ситуациях. Попробуй хотя бы, не закончив таскать объект, переключится в другое приложение и что-нибуль там поделать. Кроме того, драг&дроп удобнее реализовывать на уровне парента. Примерно так:
|
| Автор: OverBug 27.11.2006, 16:14 |
| а как задать области где перетаскиваемый объект можно бросать? тут без оли можно обойтись или нет? |
| Автор: Earnest 27.11.2006, 16:23 |
| Области окна, в котором осуществляется драг? Элементарно. На MouseMove проверяй, где мышь, и, если вне области дозволенного дропа, показывай курсор-дулю (ну такой стандартный перечеркнутый круг) вместо перерисовки контрола. А при нормальной позиции - не забудь его спрятать. На дроп придется проверить то же самое, или флаг веди. |
| Автор: OverBug 27.11.2006, 16:35 |
| т.е.,как я понял, в условии драггинга появятся два условия: одно - если область дозволенная, другое - все остальные случаи.... и проверять на дозволенность позиции можно сразу по нескольким областям.... а в случае между окнами, хотябы двух копий одного и тогоже приложения.... или его тулвиндовов??? |
| Автор: Earnest 27.11.2006, 17:20 |
| Тогда сложнее. Из OnMouseMove нужно опрашивать окно под курсором, не желает ли оно принять объект. Для этого нужно ввести свое сообщение, в wParam, lParam можно передать дополнительные параметры, а в случае отказа должен возвращаться 0, чтобы окна, не обрабатывающие твое сообщение, адекватно реагировали. Но, как ты понимаешь, совсем чужое окно твое сообщение не примет. |
| Автор: OverBug 29.11.2006, 12:28 |
| интересно... но ведь под курсором то окно которое я тащу.... перетаскиваю.... как получить то которое ниже? и если я буду проверять на области в которых дозволено бросать объект.... надо ведь еще и массив этих координат не только хранить, но и поддерживать в актуальном состоянии. а как это лучше сделать? |
| Автор: Earnest 29.11.2006, 12:46 |
| Нет, если ты спросишь WindowFromPoint, то тебе вернут окно верхнего уровня (не Child). Если хочешь получить child, нужно опрашивать ChildWindowFromPoint. Каждое окно, которое может принять объект, пусть и хранит само свои области. |
| Автор: OverBug 29.11.2006, 12:56 |
| понятненько.... спасибо.... как будет готова полная версия выложу ее на всеобщее обозрение.... |
| Автор: CityAC 15.3.2007, 00:22 | ||
| Тоже столкнулся с такой задачей. Прочитал эту ветку. Никак не могу понять. Если нужно таскать кнопку, то она же не реагирует на события мыши прописанные для диалога.
Так как же таскать кнопки. Что для каждой кнопки нужно писать свой обработчик, а если у меня из 32 шт? |
| Автор: Earnest 15.3.2007, 09:32 |
| Лови в PreTranslateMessage диалога. |
| Автор: CityAC 15.3.2007, 13:05 | ||
Как из pMsg извлечь информацию кто послал сообщение, т.е. какая кнопка была нажата? |
| Автор: CityAC 15.3.2007, 13:37 | ||
Я сделал так
но получается нужно этот код прописывать для всех кнопок, которые планируешь таскать. Наверно все таки нужно вытягивать инфу из pMsg/ Подскажите как |
| Автор: Earnest 15.3.2007, 14:14 |
| В сообщении нет такой информации. Но ты элементарно можешь найти, над каким контролом в настоящий момент находится мышь: ChildWindowFromPoint (что-то в этом роде). |
| Автор: CityAC 15.3.2007, 16:47 | ||
| да спасибо. Я вычитал эту функцию в вашем же посте в этой ветке. Но что значит Child в данном случае. кнопка ОК - это child?
|
| Автор: zkv 15.3.2007, 17:13 |
кнопка Ок - это child-окно своего диалога также child-окнами диалога являются все остальные контролы этого диалога |
| Автор: CityAC 16.3.2007, 11:43 | ||||
Разобрался, нужно было pMsg->pt привести к клиетским координатам |
| Автор: 13dreams 4.7.2010, 10:31 |
| Простите, как изменить координаты самой кнопки использую вышеизложенный код? (как её перерисовать) |
| Автор: Earnest 5.7.2010, 09:32 |
| Перечитывать древний топик сильно влом, поэтому отвечу "наугад" - MoveWindow? |
| Автор: 13dreams 5.7.2010, 13:24 |
| Задача состоит в том, чтобы пользователь мог перетащить созданную кнопку по окну я хотел спросить где и как реализуется само изменение её координат |
| Автор: 13dreams 5.7.2010, 15:48 | ||
| В принципе я разобрался. Использую вышеприведённый код - в (PreTranslateMessage) для того чтобы ловить на какой кнопке был совершён клик пользуюсь сообщением WM_LBUTTONDOWN. Устанавливаю там флаг и дальше в WM_LBUTTONUP двигаю кнопку в координаты где находился курсор в данный момент. Но не получается преобразовать координаты курсора
Ошибка - невозможно преобразовать из CPoint в LPPOINT как получить координаты курсора (или преобразовать их) |
| Автор: Albor 5.7.2010, 16:14 |
LPPOINT это указатель, а не объект CPoint. Поэтому нужно делать операцию взятия адреса как в GetCursorPos(&tpoint); |
| Автор: 13dreams 5.7.2010, 17:31 | ||||
Спасибо большое! Всё получилось но один момент : пришлось вместо строки
т.к. объект двигался на небольшом расстоянии от курсора Чего так происходит? Я так понимаю нужно что-то к чему-то привести? ps и если кто-то захочет использовать код - я определил флаг не в том месте. Его нужно определить где-то повыше |
| Автор: 13dreams 9.7.2010, 09:09 | ||||
| Пожалуйста, помогите довести до конца пример решил использовать приведённую выше идею чтобы сократить код
Работает некорректно. 1. Выше написано что нужно (pMsg->pt) привести к клиентским координатам. Как это сделать? 2. Как выполнить проверку на то, что не получен указатель на главное окно? Чтоб окно не реагировало на код изменения положения Заранее спасибо! |
| Автор: Ghost99 18.12.2011, 02:39 | ||
| Я таки дико извиняюсь,что поднимаю мертвую тему но... Можно использовать сообщения в не клиентскую область окна: Наследник от CButton:
тут есть единственная промблемма - как получить сообщение, что левая кнопка отпущена и передать это контроллу? Перемещение работает, но конторол после перемещения ведет себя не адекватно: сообщение WM_LBUTTONUP не ловит - при наведении на него отображается как нажатый. Может быть хук поставить? |
| Автор: Earnest 18.12.2011, 18:14 |
| Не хук, а капчу (SetCapture). Это обычный прием при обработке drag & drop. Тогда все мышиные события будут приходить твоей кнопке, независимо от позиции мыши - пока не отпустишь. |