Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Не поймать WM_MOUSEMOVE во время нажатия на кнопку, в оконном цикле обработки сообщений 
:(
    Опции темы
Mapa3M
Дата 29.8.2008, 00:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



сабж.   Хочу нажать на кнопку и перетащить ее в другую часть окна. Но, когда зажимаю левую кнопку мыши и перетаскиваю, окну приходят только WM_CTLCOLORBTN. А нужное мне WM_MOUSEMOVE, как показывает Spy++ приходят кнопке (тоесть когда ставлю хук на кнопку - ловлю, а когда на окно - нет)

Я буквально только-что начал знакомится с Win API, не судите строго. Расскажите пожалуйста, как поймать WM_MOUSEMOVE?  Возможно ли создать, если да то как, отдельную CALLBACK для кнопки ?

Это сообщение отредактировал(а) Mapa3M - 29.8.2008, 03:08
PM MAIL   Вверх
BorisVorontsov
Дата 29.8.2008, 20:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Thinker
**


Профиль
Группа: Комодератор
Сообщений: 714
Регистрация: 3.11.2005
Где: Молдавия, г. Киши нёв

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



ReleaseCapture?


--------------------
[code=cpp]
const char *out = "|*0>78-,+<|"; size_t cc = char_traits<char>::length(out);
for (size_t i=0;i<cc;i++){cout<<static_cast<char>((out[i]^89));}cout<<endl;
[/code]
PM MAIL ICQ GTalk   Вверх
Mapa3M
Дата 29.8.2008, 23:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(BorisVorontsov @  29.8.2008,  20:01 Найти цитируемый пост)
ReleaseCapture


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


Это сообщение отредактировал(а) Mapa3M - 30.8.2008, 01:27
PM MAIL   Вверх
Mapa3M
Дата 30.8.2008, 04:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Кстати, чегото неполучается поставить SetCapture по сообщению WM_PARENTNOTIFY. 
По другим сообщениям получается, здесь чота никак не срабатывает.  Сообщение приходит что каптча поставлена на кнопку, хотя я ставлю на окно. Как так?

Это сообщение отредактировал(а) Mapa3M - 30.8.2008, 04:46
PM MAIL   Вверх
586
Дата 30.8.2008, 04:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2243
Регистрация: 8.5.2006

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



Код
long OldBtnProc;

LRESULT CALLBACK MyButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
     case WM_LBUTTONDOWN:
        ReleaseCapture();  // нужно для сообщения 0xF012
        SendMessage(hWnd, WM_SYSCOMMAND, 0xF012, 0);
        return 0;

    }
    return CallWindowProc((WNDPROC)OldBtnProc, hWnd, uMsg, wParam, lParam);
}


OldBtnProc = SetWindowLong(hWnd, GWL_WNDPROC, (long)MyButtonProc);

PM   Вверх
Mapa3M
Дата 30.8.2008, 04:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



586,   Спасиб, то что надо! Буду пробовать...
PM MAIL   Вверх
Mapa3M
Дата 30.8.2008, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(586 @  30.8.2008,  04:41 Найти цитируемый пост)
        ReleaseCapture();  // нужно для сообщения 0xF012
        SendMessage(hWnd, WM_SYSCOMMAND, 0xF012, 0);


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

Кстати, откуда 0xF012? В MSDNе ниче не нашел.
PM MAIL   Вверх
586
Дата 30.8.2008, 15:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2243
Регистрация: 8.5.2006

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



Цитата(Mapa3M @  30.8.2008,  15:13 Найти цитируемый пост)
Кстати, откуда 0xF012? В MSDNе ниче не нашел. 

Это народный метод. Работает только для левой кнопки. Написал здесь просто для примера - твой вопрос же был, как перехватить оконную процедуру.
Если хорошенько подумать, то можно и с координатами:
Код
#include <windowsx.h>  // GET_X_LPARAM and GET_Y_LPARAM

long OldBtnProc;
LRESULT CALLBACK MyButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static POINT ptOld;
    static int x, y;        // позиция указателя на кнопке
    static bool bMove = false;
    POINT pt;


    switch(uMsg)
    {
     case WM_RBUTTONDOWN:
        SetCapture(hWnd);
        x = GET_X_LPARAM(lParam);
        y = GET_Y_LPARAM(lParam);
        GetCursorPos(&ptOld);
        ScreenToClient(GetParent(hWnd), &ptOld);
        bMove = true;
        return 0;

     case WM_MOUSEMOVE:
        if(bMove)
        {
            GetCursorPos(&pt);
            ScreenToClient(GetParent(hWnd), &pt);

            SetWindowPos(hWnd, 0, ptOld.x - x, ptOld.y - y,
                0, 0, SWP_NOSIZE);
            ptOld = pt;
        }
        return 0;

     case WM_RBUTTONUP:
     case WM_CAPTURECHANGED:
        ReleaseCapture();
        bMove = false;
        return 0;
    }
    return CallWindowProc((WNDPROC)OldBtnProc, hWnd, uMsg, wParam, lParam);
}

Код
#include <windowsx.h>

long OldBtnProc;
LRESULT CALLBACK MyButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static int x, y;                     // клиентские коорд. места, где находится курсор
    static RECT wndrect;          // коорд. кнопки относительно родителя
    static bool bMove = false;

    switch(uMsg)
    {
     case WM_RBUTTONDOWN:
        SetCapture(hWnd);
        x = GET_X_LPARAM(lParam);
        y = GET_Y_LPARAM(lParam);
        GetWindowRect(hWnd, &wndrect);
        wndrect.right -= wndrect.left;
        wndrect.bottom -= wndrect.top;
        ScreenToClient(GetParent(hWnd), (LPPOINT)&wndrect);
        bMove = true;
        return 0;

     case WM_MOUSEMOVE:
        if(bMove)
        {
            wndrect.left += GET_X_LPARAM(lParam) - x;
            wndrect.top += GET_Y_LPARAM(lParam) - y; 

            /*wndrect.left += (short)LOWORD(lParam) - x;
            wndrect.top += (short)HIWORD(lParam) - y; */

            SetWindowPos(hWnd, 0, wndrect.left, wndrect.top,
                0, 0, SWP_NOSIZE);
        }
        return 0;

     case WM_RBUTTONUP:
     case WM_CAPTURECHANGED:
        ReleaseCapture();
        bMove = false;
        return 0;
    }
    return CallWindowProc((WNDPROC)OldBtnProc, hWnd, uMsg, wParam, lParam);
}


Это сообщение отредактировал(а) 586 - 30.8.2008, 16:24
PM   Вверх
GremlinProg
Дата 30.8.2008, 16:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

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



мда уж, не думал, что тема до такого марадерства дойдет...

Mapa3M, сообщение мыши приходят в окно, над которым она находится, т.е., если ты кликаешь на кнопку, то WM_LBUTTONDOWN и придет в кнопку, т.е. в процедуре диалога оно само не объявится.

чтобы перехватить процедуру окна любого контрола, необходимо воспользоваться специально предназначенного для этого API, вот пример такого перехвата (корректная версия с поддержкой w64):
Код

OldWndProc = (WNDPROC)SetWindowLongPtr (hButton,GWLP_WNDPROC, (LONG_PTR)NewWndProc);

версия с включенной поддержкой w64, это 32-битная версия, (стандартная ошибка локализации, на x64 работать не будет!):
Код

OldWndProc = (WNDPROC)SetWindowLong(hButton,GWL_WNDPROC, (LONG)(LONG_PTR)NewWndProc);

версия с выключенной поддержкой w64 (без ошибок и без x64):
Код

OldWndProc = (WNDPROC)SetWindowLong(hButton,GWL_WNDPROC, (LONG)NewWndProc);

NewWndProc - это процедура кнопки, которая после такого будет вызываться вместо стандартной (OldWndProc)
стратегия NewWndProc должна составлять хотя бы такой минимум:
Код

LRESULT CALLBACK NewWndProc(HWND hButton,UINT message,WPARAM wParam,LPARAM lParam){
  return::CallWindowProc(OldWndProc,hButton,message,wParam,lParam);
}

такой перехват нужно делать сразу после инициализации диалога, например в WM_INITDIALOG

если нужен перехват WM_LBUTTONDOWN, то это можно сделать так:
Код

LRESULT CALLBACK NewWndProc(HWND hButton,UINT message,WPARAM wParam,LPARAM lParam){
  switch(message){
    case WM_LBUTTONDOWN:{
      // код сообщения WM_LBUTTONDOWN, которое произошло над кнопкой
      break;
    }
  }
  return::CallWindowProc(OldWndProc,hButton,message,wParam,lParam);
}

вариант#1:
перемещение кнопки нужно сопрягать по крайней мере с тремя сообщениями мыши:

1. WM_LBUTTONDOWN
2. WM_MOUSEMOVE
3. WM_LBUTTONUP

в первом нужно запомнить позицию мыши относительно левого-верхнего угла кнопки (sx,sy) = (x - left,y - top) и включить флаг переноса
во втором нужно тестировать флаг переноса, и если он включен, переместить кнопку в позицию (x - sx,y - sy)
в третьем нужно сбросить флаг переноса

флаг переноса - просто любая глобальная переменная, изначально проинициализированная нулем

вариант#2:
корректное перемещение включает еще дополнительное сообщение:
4. WM_CAPTURECHANGED
при этом, на WM_LBUTTONDOWN нужно еще вызвать SetCapture, а на WM_LBUTTONUP вызвать ReleaseCapture, флаг переноса сбрасывать уже не на WM_LBUTTONUP, а в сообщении WM_CAPTURECHANGED, остальное - так же как в первом варианте.

попробуй оба варианта, разницу сам увидишь

тебе как нужно кнопку двигать? зажатую или не зажатую, или это не важно?
если не зажатую, то во время перехвата WM_LBUTTONDOWN, не выполняй стандартную обработку окна, т.е. вместо break вызови return 0 этим ты предотвратишь стандартную инициализацию механизма нажатия (в том числе и SetCapture), но тогда уже и нажиматься кнопка не будет.

Это сообщение отредактировал(а) GremlinProg - 30.8.2008, 16:53


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Mapa3M
Дата 30.8.2008, 18:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



586, О, гуру, открой мне источник своей мудрости! (Не хочу по два дня ковырять ивзращенный код того, что делается в две строчки еще и лучше)  =))
З.Ы. извиняюсь, подскажите книжку...

Цитата(586 @  30.8.2008,  15:45 Найти цитируемый пост)

Это народный метод. Работает только для левой кнопки. 

хм, учту.  Метод понравился, спасибо. 


Цитата(586 @  30.8.2008,  15:45 Найти цитируемый пост)
Если хорошенько подумать, то можно и с координатами:

вот примерно так я и делал. Только с координатами помучался, ибо GetParent функции не знал, и без SetCapture. Зачем он в таком коде? Чтоб с другими обектами конфуз не вышел?


GremlinProg, спасибо за подробный разбор полетов. 

Это сообщение отредактировал(а) Mapa3M - 30.8.2008, 18:53
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




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


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

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