Кнопка под курсором (Передать сообщение WM_DRAWITEM)

Тема в разделе "WASM.WIN32", создана пользователем piritus, 13 апр 2008.

  1. piritus

    piritus Member

    Публикаций:
    0
    Регистрация:
    7 июл 2007
    Сообщения:
    36
    Менять картинку кнопки удается для нормального состояния и для нажатого (по средствам обработки WM_DRAWITEM), а поменять для кнопки под курсором не удается...

    Код (Text):
    1.      .elseif uMsg == WM_MOUSEMOVE
    2.             mov tme.cbSize,sizeof TRACKMOUSEEVENT
    3.                       mov tme.dwFlags,TME_HOVER or TME_LEAVE
    4.         mov tme.dwHoverTime,HOVER_DEFAULT
    5.         mov eax,hWin
    6.         mov tme.hwndTrack,eax
    7.         invoke TrackMouseEvent,addr tme
    8.         xor eax,eax
    9.         ret
    10.        
    11.       .elseif uMsg == WM_MOUSELEAVE
    12.         mov tme.cbSize,sizeof TRACKMOUSEEVENT
    13.                       mov tme.dwFlags,TME_HOVER
    14.         mov tme.dwHoverTime,HOVER_DEFAULT
    15.         mov eax,hWin
    16.         mov tme.hwndTrack,eax
    17.         invoke TrackMouseEvent,addr tme
    18. ;      если курсор над кнопкой, то выполняем действия по замене картинки
    19. ; для проверки вставлял MessageBox - срабатывает при наведении на кнопку
    20.      
    21.       .elseif uMsg == WM_MOUSEHOVER
    22.         mov tme.cbSize,sizeof TRACKMOUSEEVENT
    23.                       mov tme.dwFlags,TME_LEAVE
    24.         mov tme.dwHoverTime,HOVER_DEFAULT
    25.         mov eax,hWin
    26.         mov tme.hwndTrack,eax
    27.         invoke TrackMouseEvent,addr tme
    я так понимаю, что нужно SendMessage выполнить... (или можно как-то еще?)
    Код (Text):
    1. invoke SendMessage,hWin,WM_DRAWITEM,IDButton,здесь нужно вставить ссылку на DRAWITEMSTRUCT
    где брать ссылку не знаю... Ведь когда система посылает WM_DRAWITEM, ссылку она сама передает...
    Я вобще то делаю? :)
     
  2. Rascalspb

    Rascalspb New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    46
    Адрес:
    СПб
    что требуется то? хайлайтить кнопку при наведении мышки?
    самый простой путь - сабклассить окно и перерисовывать, без помощи системы. Сложность будет тока с гемором изображения на кнопке итп. И гуглить не пробовал? чтото подсказывает, что есть куча примеров =)
     
  3. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    piritus
    что то все забывают смотреть сам сайт:dntknw:
    дочерта разных интересных примеров в разделе исходники
     
  4. masm32

    masm32 New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2008
    Сообщения:
    147
    WM_MOUSELEAVE - надо с ним разобраться...обычно окно не получает это сообщение, вроде бы...
    Найдёшь пример - дай ссылку пож-ста . Сделал офф-лайновую версию форума за прошлый месяц - час ковырялся так и не нашёл ... нужно поиск присобачить как-то к chm
     
  5. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    проще самому нарисовать, чем морочиться с wm_drawitem.
    С рисованием изображения тоже проблем нет: использовать иконки и GetIconInfo для позиционирования изображения.

    После получения WM_MOUSEHOVER надо сбросить (TME_CANCEL or TME_HOVER) тракинг, а затем перезапускать TrackMouseEvent на покидание (TME_LEAVE) кнопки.
     
  6. piritus

    piritus Member

    Публикаций:
    0
    Регистрация:
    7 июл 2007
    Сообщения:
    36
    masm32, окно получает WM_MOUSEMOVE, а TrackMouseEvent вызывает WM_MOUSEHOVER и WM_MOUSELEAVE
    Код (Text):
    1. mov tme.cbSize,sizeof TRACKMOUSEEVENT
    2. mov tme.dwFlags,TME_HOVER or TME_LEAVE
    3. mov tme.dwHoverTime,HOVER_DEFAULT
    4. mov eax,hWin
    5. mov tme.hwndTrack,eax
    6. invoke TrackMouseEvent,addr tme
    wsd, на сайте смотрел, но нашел примеры только с использованием каких-то левых библиотек...
    пробовал еще так:

    Код (Text):
    1. invoke LoadBitmap,hInstance,IDBtnImg
    2. mov hBtnIng, eax
    а в WM_MOUSELEAVE
    Код (Text):
    1. invoke GetDlgItem,hWin,IDButton
    2. invoke SendDlgItemMessage,hWin,eax,BM_SETIMAGE,IMAGE_ICON,hBtnIng
    Но никакого результата...
     
  7. letika

    letika New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2007
    Сообщения:
    28
    piritus
    1) Убери TME_HOVER - в нём нет смысла. Заведи булеву переменную ("курсор над кнопкой?") и on-mouse-move просто проверяй её. Если это первое движение курсора над кнопкой, то перерисовывай последнюю. В on-mouse-leave сбрасывай переменную и снова перерисовывай. Либо вместо переменной стиль какой.
    2) Перерисовка делается кучей способов, например, через InvalidateRect.
     
  8. piritus

    piritus Member

    Публикаций:
    0
    Регистрация:
    7 июл 2007
    Сообщения:
    36
    Дело в том, что у меня диалоговое окно, а InvalidateRect посылает сообщение WM_PAINT
    С вызовом WM_DRAWITEM не разобрался
    А если использовать RedrawWindow, то программа вылетает...
     
  9. piritus

    piritus Member

    Публикаций:
    0
    Регистрация:
    7 июл 2007
    Сообщения:
    36
    Так же пробовал:

    Код (Text):
    1. invoke GetDlgItem,hWin,1000
    2. mov hBtn, eax
    3. invoke LoadImage,NULL,offset szBtnSel,IMAGE_BITMAP,0,0,LR_LOADFROMFILE
    4. mov hBtnOK,eax
    5. ;........
    6. ; в WM_MOUSELEAVE вызываю
    7. invoke SendMessage,hBtn, BM_SETIMAGE, IMAGE_BITMAP, hBtnSel
    Но кнопка не перерисовывается (хотя тестовый MessageBox работает при наведении на кнопку)
    Может эти способы не годятся для диалогового окна?

    Кажется понял в чем проблема:
    После вызова
    SendDlgItemMessage или SendMessage
    в eax 0
    В диалоге вобще SendMessage работает?
     
  10. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    >>Дело в том, что у меня диалоговое окно, а InvalidateRect посылает сообщение WM_PAINT

    Не посылает.

    >>А если использовать RedrawWindow, то программа вылетает...

    Программа, которая вылетает из-за RedrawWindow ??

    >В диалоге вобще SendMessage работает?

    Работает, работает, без паники :)
     
  11. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Пока пытаешься прицепить BM_SETIMAGE, давно бы сам нарисовал бы все состояния: hover, leave, down, up.
    Если не хочется всё рисовать самому, часть операций можно переложить на defwindowproc
    На скорую руку:
     
  12. piritus

    piritus Member

    Публикаций:
    0
    Регистрация:
    7 июл 2007
    Сообщения:
    36
    В описании InvalidateRect:
    "...Windows sends a WM_PAINT message to a window whenever its update region is not empty and there are no other messages in the application queue for that window..."
    Может я как-то не так понял...

    cresta, исходник можно глянуть?

    и такой еще вопрос:
    в каких случаях SendMessage возвращает NULL?
    почему-то на
    invoke SendMessage,hBtn, BM_SETIMAGE, IMAGE_BITMAP, hBtnSel
    он в eax 0 пишет, а при
    invoke SendMessage, hWin, WM_SETTEXT, 0, ADDR dlgTitle
    в eax 1

    разве в диалоге нельзя вызывать BM_SETIMAGE?
     
  13. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    piritus
    Где ты такое описание увидел?
    Для форсирования обновления добавляй UpdateWindow.
     
  14. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    можно.

    Где-то у меня валялся полноценный стандартный виндовый button с поддержкой смены картинки по hover/leave
    Если найду - тоже приаттачу
     
  15. piritus

    piritus Member

    Публикаций:
    0
    Регистрация:
    7 июл 2007
    Сообщения:
    36
    ошибка №57A при вызове DrawIconEx... :dntknw:
    что-то я вобще наворотил в программе, почти все функции не работают...
     
  16. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    если это код ошибки, возвращаемый getlasterror, то это ERROR_INVALID_CURSOR_HANDLE.
    Причём здесь курсор? Ты что, курсор пытаешься рисовать?
    Или битмап??
    Там рисунок нужен иконка (.ico). А не битмап и не курсор.


    Тот проект, что обещал, где-то затерялся....
    Вот ещё один на скорую руку:
    Алго примерно такой:
    1. При первой прорисовке кнопки по WM_PAINT создаем mDC (CreateCompatibleDC) в памяти и когда винда отрисовала нам по CallWindowProc эту кнопку, мы её изображение прячем (копируем) в этом mDC.
    Оно там будет храниться все время.
    2. Когда нам нужно изображение ненажатой кнопки (по WM_PAINT, WM_MOUSEHOVER, WM_MOUSELEAVE, WM_LBUTTONUP), будем брать этот спрятаный рисунок, отрисовывать его (BitBlt) в текущий hDC кнопки, а потом поверх отрисованного рисовать нужную иконку и рисовать текст.


    Как это выглядит - в аттаче.
    Там ещё надо слегка доработать. Возможно, кроме ненажатого, надо будет ещё и нажатое состояние хранить, чтобы не было траблов с манифестами. Но это надо пробовать.
     
  17. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    Для контраста - вот пример по формуле DIALOG+WM_SETCURSOR+BM_SETIMAGE+CURSOR:

    Код (Text):
    1. .386
    2. .model flat,stdcall
    3. option casemap:none
    4.  
    5. include    \masm32\include\windows.inc
    6. include    \masm32\include\user32.inc
    7. include    \masm32\include\kernel32.inc
    8. includelib \masm32\lib\user32.lib
    9. includelib \masm32\lib\kernel32.lib
    10.  
    11. .data
    12. .data?
    13.  hcur1 dd ?
    14.  hcur2 dd ?
    15.  hcur3 dd ?
    16. .code
    17.  
    18. DlgProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
    19.  
    20.   .if   uMsg==WM_CLOSE
    21.     invoke EndDialog,hWnd,0
    22.  
    23.   .elseif uMsg==WM_INITDIALOG
    24.     invoke LoadCursor,0,IDC_HELP
    25.     mov hcur1,eax
    26.     invoke LoadCursor,0,IDC_HAND
    27.     mov hcur2,eax
    28.     invoke LoadCursor,0,IDC_APPSTARTING
    29.     mov hcur3,eax
    30.     jmp @f
    31.  
    32.   .elseif uMsg==WM_SETCURSOR
    33.     mov eax,wParam
    34.     .if eax==hWnd
    35. @@:
    36.       mov eax,hcur1
    37.     .else
    38.       mov eax,lParam
    39.       shr eax,16
    40.       .if eax==WM_LBUTTONDOWN    
    41.         mov eax,hcur3
    42.       .else
    43.         mov eax,hcur2
    44.       .endif
    45.     .endif
    46.     invoke SendDlgItemMessage,hWnd,123,BM_SETIMAGE,IMAGE_ICON,eax
    47.     jmp @f
    48.   .else
    49. @@:
    50.     xor eax,eax
    51.     jmp @f
    52.   .endif
    53.   xor eax,eax
    54.   inc eax
    55. @@:
    56.   ret
    57. DlgProc endp
    58.  
    59. start:
    60.   invoke GetModuleHandle,0
    61.   invoke DialogBoxParam,eax,123,0,addr DlgProc,0
    62.   invoke ExitProcess,eax
    63. end start
    64.  
    65. ; // .rc
    66.  
    67. ; #include "\masm32\include\resource.h"
    68. ;
    69. ; 123 DIALOGEX 0,0,150,80
    70. ; STYLE WS_OVERLAPPEDWINDOW | DS_CENTER
    71. ; EXSTYLE WS_EX_TOPMOST
    72. ; CAPTION "CURSOR  &  BUTTON"
    73. ; {
    74. ;  CONTROL "",123,BUTTON,   WS_CHILD | WS_VISIBLE | BS_ICON,10,10,30,30
    75. ; }
    Правда, и мой пример, и пример от cresta не учитывают хулиганскую возможность прижатия кнопки и оттаскивании мышки с кнопки без ее отжатия...
     
  18. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    оттаскивание нажатой мыши от кнопки регулируется простой булевой переменной.
    А вот с манифестом проблема более серьезная.
    Если использовать манифест, то в зависимости от того, какие темы могут быть включены у юзера, поток сообщений выглядит совершенно по разному: и количество сообщений, и их очередность меняются по сценарию, в котором я не смог определить какую-то закономерность.
    Например в классическом XP по отпусканию мыши происходит только WM_LBUTTONUP и больше никаких сообщений.
    С темой Luna при отпускании после каждого из обрабатываемых в примере сообщений приходит ещё и WM_PAINT. А это сбивает всю логику. Блокировать WM_PAINT, чтобы не перетирал отрисованное по WM_LBUTTONUP нельзя (а вдруг этот WM_PAINT не после WM_LBUTTONUP), а детерминировать, что это за WM_PAINT: после WM_LBUTTONUP или сам по себе, не представляется возможным. По крайней мере какими-то надёжными способами.

    По-моему, лучшее решение - просто сделать свой контрол. От и до. Не полагаясь на графическую подсистему ОС.
     
  19. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Угу, сталкивался с тем, что поведение различается для разных систем. В частности, 2к любит перерисовывать контролы, вызывая внутренние функции напрямую, минуя сообщения.
     
  20. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Блин, никак не удаётся сделать абсолютно одинаково с включеным манифестом и без него.

    Если с манифестом, то не получается цвет текста поменять по нажатию. Хотя может это и не надо.
    А по поводу картинки hover/leave/down состояния нормально отслеживаются, для каждого можно свой рисунок (иконку) отрисовать. И рамка фокуса вокруг кнопки прорисовывается.

    piritus
    Попробуй запусти ехе-шник в аттаче, пока не перекомпилировал проект. А потом будешь экспериментировать.
    Если не подходит, дальше мучайся сам, логику что и когда делать можно там отследить. А я пошёл спать :)

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