Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.235.180.245] |
|
Сообщ.
#1
,
|
|
|
всем привет.
подскажите пожалуйста как решить задачу следующего типа. есть самописный gui, контролы рисуются на окне, т.е. окно верхнего уровня не имеет окон-чилдренов. добрался до драгдропа (WM_DROPFILES). и тут заметил неприятную штукенцию. например есть кнопка позволяющая кидать на себя файлы, естественно делаем топ-окну WS_EX_ACCEPTFILES. неприятность в том, что курсор принимает вид "можно бросить" в любом месте окна. Как сделать, чтобы курсор изменялся только находясь над кнопкой (не делая кнопку окном(HWND))? посоветуйте что-нибудь, спасибо |
Сообщ.
#2
,
|
|
|
На ум приходит только сохранение региона(-ов), которые поддерживают Drag & Drop, ну и курсор естественно менять вручную, жестоко, но коли уж вся область одно окно с рисованной GUI, то и справляться явно придётся нестандартными методами.
|
Сообщ.
#3
,
|
|
|
над подобным решением думал, но когда, например, хватаешь файл(ы) с рабочего стола и "машешь" над окном, окну сообщения вообще никакие не приходят..
|
Сообщ.
#4
,
|
|
|
Emura, WS_EX_ACCEPTFILES тут не спасёт, да. Советую почитать про RegisterDragDrop.
|
Сообщ.
#5
,
|
|
|
ок, спасибо, посмотрю что за зверь.
Spawn.NET, спасибо за помощь, работает. |
Сообщ.
#6
,
|
|
|
обнаружен при этом способе небольшой глючок в следующем.
например, - кидаем папку из эксплорера в окно (IDropTarget). - обрабатываем файлы из папки(специфика программы). окно эксплорера (откуда бралась папка) подвисает на время обработки. подскажите пожалуйста куда смотреть. были варианты решения -пока тщетно. IDropTarget::Drop такого вида. IDropTarget::Drop() { извлекаем путь папки PostMessage с путем папки; } из функции успешно выходим перед тем как приходит сообщение от PostMessage, т.е. блокировать обработка не должна.. но блокировка налицо. многопоточности нет, XP. тестовый проект #include <windows.h> static const wchar_t* const gWindowClassName =L"-TEST_CLASS_NAME-"; static const UINT WM_MAGIC =WM_APP + 0x4400; static LRESULT CALLBACK gWindowProc( HWND h, const UINT message, const WPARAM wParam, const LPARAM lParam ) { switch ( message ) { case WM_DESTROY: { ::PostQuitMessage(0); return 0; break; } case WM_MAGIC: { for ( int i=0; i<50; ++i ) { ::Sleep(100); } return 0; break; } } return ::DefWindowProcW( h, message, wParam, lParam ); }; class MyDropTarget : public IDropTarget { private: ULONG m_refCount; HWND m_owner; wchar_t m_data[1024]; public: MyDropTarget( HWND owner ): m_refCount ( 1 ), m_owner ( owner ) { } virtual ~MyDropTarget() { } HRESULT __stdcall QueryInterface( REFIID id, void FAR* FAR* result ) { if ( id==IID_IUnknown || id==IID_IDropTarget ) { *result =this; AddRef(); return NOERROR; } *result =NULL; return ResultFromScode(E_NOINTERFACE); } ULONG __stdcall AddRef() { return ++m_refCount; } ULONG __stdcall Release() { if ( --m_refCount==0 ) { delete this; return 0; } return m_refCount; } HRESULT __stdcall DragEnter( IDataObject* dataObject, DWORD grfKeyState, POINTL mousePos, DWORD* effect ) { *effect =DROPEFFECT_COPY; return NOERROR; } HRESULT __stdcall DragOver( DWORD keyState, POINTL mousePos, DWORD* effect ) { *effect =DROPEFFECT_COPY; return NOERROR; } HRESULT __stdcall DragLeave() { return NOERROR; } HRESULT __stdcall Drop( IDataObject* dataObject, DWORD keyState, POINTL mousePos, DWORD* effect ) { BOOL r =::PostMessageW( m_owner, WM_MAGIC, 0, (LPARAM)0 ); *effect =DROPEFFECT_COPY; return NOERROR; } }; INT WINAPI WinMain( HINSTANCE, HINSTANCE, char*, INT ) { ::OleInitialize(NULL); WNDCLASSEX wc; ::memset( &wc, 0, sizeof(wc) ); wc.cbSize =sizeof(wc); wc.lpfnWndProc =(WNDPROC)gWindowProc; wc.cbWndExtra =4; wc.hInstance =::GetModuleHandleW(0); wc.lpszClassName =gWindowClassName; wc.hbrBackground =(HBRUSH)::GetStockObject( WHITE_BRUSH ); wc.hCursor =::LoadCursorW( NULL, IDC_ARROW ); ::RegisterClassExW( &wc ); HWND h =::CreateWindowExW( 0, wc.lpszClassName, NULL, WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, NULL, NULL, ::GetModuleHandleW(0), NULL ); ::ShowWindow( h, SW_NORMAL ); MyDropTarget dt(h); HRESULT result =::RegisterDragDrop( h, &dt ); MSG m; while ( ::GetMessageW( &m, NULL, 0, 0 )>0 ) { ::TranslateMessage( &m ); ::DispatchMessageW( &m ); } ::RevokeDragDrop( h ); ::DestroyWindow( h ); ::UnregisterClassW( gWindowClassName, ::GetModuleHandleW(0) ); ::OleUninitialize(); return 0; }; |
Сообщ.
#7
,
|
|
|
Мне кажется это как то связано с этим куском кода
Ты тут намеренно усыпляешь все приложение на 5 секунд, собвствено приложение не реагирует вообще ни на что, с таким подходом приложение может подвесить и твой Drag and Drop case WM_MAGIC: { for ( int i=0; i<50; ++i ) { ::Sleep(100); } return 0; break; } |
Сообщ.
#8
,
|
|
|
Dem_max
sleep для примера, реально там происходит обработка файлов. тело Drop функции отрабатывается раньше чем присходит заход в блок WM_MAGIC (благодаря PostMessage), по этой причине не использовал SendMessage. думалось что explorer получает управление после Drop(), но это почему-то не так. для справки, например, если использовать WM_DROPFILES и делать обработку в блоке WM_DROPFILES то все ок, explorer не виснет. еще интересно если во время обработки выскакивает мессаджбокс(вызываемый алгоритмом обработки), то explorer размораживается.. |
Сообщ.
#9
,
|
|
|
Цитата sleep для примера Я понимаю что для примера, но он то и блокирует у тебя поток. |
Сообщ.
#10
,
|
|
|
посоветовали использовать таймер, но смахивает на костыль, попробую..
|
Сообщ.
#11
,
|
|
|
Можешь обойтись и без Ole Drag&Drop
Цитата Emura @ например есть кнопка позволяющая кидать на себя файлы, естественно делаем топ-окну WS_EX_ACCEPTFILES. неприятность в том, что курсор принимает вид "можно бросить" в любом месте окна. Как сделать, чтобы курсор изменялся только находясь над кнопкой (не делая кнопку окном(HWND))? Есть недокументированное сообщение #define WM_QUERYDROPOBJECT 0x022B Цитата WM_QUERYDROPOBJECT Значение: 0x22b Параметры: wParam 0, если курсор находится над рабочей областью окна, иначе 1. lParam Указатель на структуру DRAGINFO, содержащую информацию об операции. Комментарии: Сообщение посылается окну, над которым находится перемещаемый объект, чтобы узнать, может ли оно принять этот объект. В случае возможности приема, оконная процедура должна после обработки возвратить TRUE. Это выдержка из документации по недокументированным сообщениям Win 3.1, однако вплоть до Win XP/7 этот механизм похоже не менялся. Попробуй сам его обработать, если окну с помощью DragAcceptFiles или вручную установлен стиль WS_EX_ACCEPTFILES. В обработчике, если курсор над кнопкой возвращай TRUE, иначе FALSE. Если ты хочешь Ole Drag&Drop Цитата PostMessage с путем папки; Указатель на путь должен указывать на область памяти, которая будет актуальна и при обработке данного сообщения. for ( int i=0; i<50; ++i ) { ::Sleep(100); } Это вообще зачем ? |
Сообщ.
#12
,
|
|
|
Jenya
Ole Drag&Drop, не то что хочу, без него не обойтись, не использовал бы с радостью, если бы можно было. используется по той причине что надо контролировать вид курсора в пределах одного окна(окно - место для виджетов), специфика задачи. Цитата Указатель на путь должен указывать на область памяти, которая будет актуальна и при обработке данного сообщения. это всё учитывается, за подсказку спасибо Цитата Это вообще зачем ? это для тестового примера(код выше), как некое действие занимающее поток. на данный момент попробовал с таймером - работает. оставлю его, если более никто не подскажет другого. |
Сообщ.
#13
,
|
|
|
Всем привет! Тема давно закрыта. Но чтобы не плодить новых тем, напишу тут.
Я использую IDropTarget Мне нужно почти то же самое, о чем писал автор, НО. Если упростить, то у меня есть 2 формы - первая должна увидеть драг файла и отобразить вторую форму, которая и принимает файлы. Все прекрасно работает, кроме одного нюанса: мне нужно, чтобы первая форма, которая только сигналит второй форме о том, что начался Драг, не умела принимать файл, а только сигналить о начале драга, или о уводе мышки с окна вообще и тогда снова скрывать вторую форму, или говорить о том, что скинули файл на нее и тоже просто скрывать вторую форму. Я к чему - это все работает, но нужно, в момент, пока мышка с файлом бродит по первой форме, не залезая в область второй, мышка имела бы "запретительный" вид. У меня получается такое добиться только если в функции DragEnter я укажу Result = False. НО тогда вообще отключается проверка на Драг и например если скинуть файл на первую форму, то вторая форма так и останется висеть, хотя друг уже закончился... Как мне менять курсор мышки, не отключая механизм Драга в первой форме? |