Консультация № 72301
23.01.2007, 19:43
0.00 руб.
0 3 3
Здравствуйте. Проблемка возникла, не знаю как решить:
Есть кнопка со стилем BS_OWNERDRAW. Мне нужно, чтобы под курсором мыши она перерисовывалась(типа подсвечивалась). Вроде все делаю правильно, отслеживаю сообщения WM_MOUSEMOVE, но как
раз над этой кнопкой сообщения WM_MOUSEMOVE перестают поступать в оконную процедуру. Как это правильно делается, подскажите пожалуйста. Спасибо.
С/С++.

Обсуждение

Неизвестный
23.01.2007, 21:09
общий
это ответ
Здравствуйте, Lameruga!

Для того, чтобы правильно обработать данную ситуацию, Вам необходимо реагировать на сообщение WM_DRAWITEM.

При приеме этого сообщения:
wParam - идентификатор контрола;
lParam - указатель на структуру DRAWITEMSTRUCT.

DRAWITEMSTRUCT.itemState в Вашем случае должен содержать флаг ODS_HOTLIGHT.

Флаг ODS_HOTLIGHT действует только в Windows 98/Me, Windows 2000/XP.
На старых версиях придется извращаться по-другому.

Если Вам необходимо решение и для старых версий Windows и Вы согласны немного подождать, то я мог бы немного поэкпериментировать.

Всего доброго.
Неизвестный
23.01.2007, 22:33
общий
это ответ
Здравствуйте, Lameruga!
Все верно, потому что на этом месте находится кнопка, т.е. когда курсор мыши над ней, то WM_MOUSEMOVE приходят уже ей, а не твоему окну. Можно тут сделать следущее. если ты пишешь под mfc, то просто унаследуйся от CButton, добавь метод OnMouseMove и соответствующую строчку в таблицу сообщений (ON_WM_MOUSEMOVE), затем перерисовывай кнопку в этом методе.
если же ты пишешь на чистом winapi, то сабклась (subclass) окно кнопки (получи ее оконную процедуру с помощью GetWindowLong, замени ее на свою с помощью SetWindowLong). в своей оконной процедуре проверяй сообщение и инициируй перерисовку.
Неизвестный
23.01.2007, 23:04
общий
это ответ
Здравствуйте, Lameruga!

> Такое впечатление, что этот прямоугольник "вырезан" из окна

Именно вырезан. Это пространство принадлежит другому окну.
Ваша кнопка, как и любой другой контрол вроде Edit или ComboBox, тоже является окном. Любое окно имеет свой класс. Оконные классы этих контролов - глобальные, их не нужно создавать самостоятельно, они существуют в системе. У каждого оконного класса - своя оконная процедура. У всех кнопок класса Button оконная процедура одна, но она не имеет ничего общего с вашей оконной процедурой родительского окна. Поэтому нет смысла ожидать, что сообщения WM_MOUSEMOVE будут приходить в вашу процедуру. Они приходят в процедуру класса Button, скрытую от ваших глаз. Существует способ подменить эту стандартную процедуру на созданную вами, путем сообщения системе о том, что данный оконный класс должен использовать адрес вашей процедуры, вместо старого адреса (используется функция SetClassLong с параметром GCL_WNDPROC). В этом случае создается специальная процедура, которая будет обрабатывать нужные сообщения класса Button, а все остальные - передавать в старую процедуру (но только через CallWindowProc, при этом сначала необходимо сохранить адрес старой процедуры). Или же можно сообщить системе, что отдельный экземпляр окна должен использовать адрес вашей процедуры, вместо старого адреса (используется функция SetWindowLong с параметром GWL_WNDPROC). Этот метод называется субклассированием (subclassing). Но для ваших целей достаточно воспользоваться методом, предложенным экспертом burbot. Дам некоторые пояснения. Сообщение WM_DRAWITEM будет посылаться системой в процедуру вашего родительского окна, в случае, если оно имеет дочерний контрол (Button, ComboBox и т.п.), созданный со стилем XX_OWNERDRAW, в тот момент, когда его экземпляр окна должен быть перерисован (например, при наведении курсора).
Будет лучше, если вы прочтете подробно о сообщении WM_DRAWITEM в справке.
Удачи!
Форма ответа