Как перерисовать только изменения окна?

Тема в разделе "WASM.WIN32", создана пользователем San1, 3 ноя 2004.

  1. San1

    San1 New Member

    Публикаций:
    0
    Регистрация:
    3 ноя 2004
    Сообщения:
    4
    При получении моим окном WM_PAINT я должен перерисовать в своем rect`е изображение. Для этого я должен постояно знать/хранить что и где мне надо нарисовать. Не хачу!

    Надо чтоб то что я уже нарисовал, не перерисовывалось, а я отрисовывал только изменения. Т.е. есть задача, еложу мышкой где-нибудь давлю кнопарь у меня там рисуется символ. И вот не хочется мне хранить все координаты тыканья этой мыши, чтобы коректно отображать экран. Может кто знает как быть в данном случае?

    Вопрос второй, как я могу узнать rect вышележашего окна, т.е. того которое закрывает какую-либо мою область окна?

    Заранее благодарю, и прошу прощения за такие глупые вопросы :).
     
  2. cresta

    cresta Active Member

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





    Там - это где? На кнопке? Или в окне? Если на кнопке, то вынеси сообщения для кнопки в отдельную процедуру, и не надо будет рисовать окно, только для кнопки будешь обрабатывать сообщения. Если в окне, пробуй GetUpdateRect по WM_PAINT



    При WM_PAINT обычно вызывается BeginPaint, она заполняет структуру PAINTSTRUCT, в которой есть такое:

    rcPaint

    Specifies a RECT structure that specifies the upper left and lower right corners of the rectangle in which the painting is requested, in device units relative to the upper-left corner of the client area.



    Если это всё не то, расшифруй вопрос, а то уж больно криво задан :)
     
  3. San1

    San1 New Member

    Публикаций:
    0
    Регистрация:
    3 ноя 2004
    Сообщения:
    4
    Криво задавать вопросы - это я умею :)

    Расшифрую что хочу получить...

    Обрабатываю сообщения о движении мыши, когда юзерь давит кнопку мыши, то совершается некоторое дейсвие над экраном (пусть для простоты печатается, нет, пусть лучше рисуется какой то символ) После этого вызываю InvalidateRect.

    В результате получаю WM_PAINT, и конечно структуру с описанием координат области для перерисовки окна. Вот теперь самое интересное, как мне сделать так чтобы сохранить на экране то, что уже там было прорисовано. у меня происходит полное перерисовка области rect.

    Просто только начинаю копаться в win32 и не знаю за что зацепится.
     
  4. San1

    San1 New Member

    Публикаций:
    0
    Регистрация:
    3 ноя 2004
    Сообщения:
    4
    Написал вот такое...

    Код (Text):
    1.  


    Displ db "DISPLAY",0

    Char WPARAM 20h



    WndProc PROC hWnd: HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    LOCAL hdc :HDC

    LOCAL hdcD :HDC

    LOCAL ps :PAINTSTRUCT

    LOCAL rect :RECT

    LOCAL hfont :HFONT



    .IF uMsg==WM_DESTROY

    invoke DeleteDC, hdc

    invoke PostQuitMessage, 0

    .ELSEIF uMsg==WM_CREATE

    invoke CreateDC, addr Displ,0,0,0

    mov hdcD, eax

    invoke CreateCompatibleDC, eax

    mov hdc,eax

    invoke GetDeviceCaps, hdcD, HORZRES

    push eax

    invoke GetDeviceCaps, hdcD, VERTRES

    pop ebx

    invoke CreateCompatibleBitmap, hdc, eax, ebx

    invoke SelectObject, hdc, eax



    invoke DeleteDC, hdcD

    .ELSEIF uMsg==WM_CHAR

    mov eax, wParam

    mov Char,eax



    invoke TextOut, hdc, 0, 0,offset Char, 1



    invoke InvalidateRect, hWnd, 0,1

    .ELSEIF uMsg==WM_RBUTTONDOWN

    mov eax,lParam

    call MoveMouse

    RGB 255, 0, 0

    invoke SetTextColor, hdc, eax

    invoke TextOut, hdc, hitpoint.x, hitpoint.y,addr Char, 1



    invoke InvalidateRect,hWnd,0,1

    .ELSEIF uMsg==WM_MOUSEMOVE

    mov eax,lParam

    call MoveMouse

    .ELSEIF uMsg==WM_PAINT

    invoke BeginPaint, hWnd, addr ps

    mov hdcD, eax

    invoke GetClientRect, hWnd, addr rect

    mov eax, rect.bottom

    sub eax, rect.top

    mov ebx, rect.right

    sub ebx, rect.left

    invoke BitBlt, hdcD, rect.left, rect.top, ebx, eax, hdc, rect.left, rect.top, SRCCOPY

    call GetLastError



    invoke EndPaint, hWnd, addr ps

    .ELSE

    invoke DefWindowProc, hWnd, uMsg, wParam, lParam

    ret

    .ENDIF



    xor eax,eax

    ret

    WndProc ENDP





    не работает. BitBlt ругается.



    Помогите глупому, наставте на путь истинный
     
  5. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Если ты нарисовал например при помощи DrawText или DrawIcon что-либо на своём hDC, и затем вызываешь InvalidateRect, провоцируя WM_PAINT, при этом ты потеряешь свой рисунок. Чтобы не терять, ты должен и по WM_PAINT тоже рисовать такой же рисунок. Попробуй сделать обработчик WM_PAINT таким образом, чтобы в нем можно было рисовать, печатать текст и т.д. Щас попытаюсь понятней выразится :)



    Пусть есть исходная процедура которую ты вызываешь по WM_PAINT с упрощениями примерно так:


    Код (Text):
    1. .data
    2.     SomeText    db 260 Dup(0)
    3.     hSomeIcon   dd 0
    4. .code
    5.  
    6. PaintProc proc
    7.     ;-- здесь какие-то действия, выполняемые при каждом WM_PAINT, например залить область
    8.     mov hDC, FUNC(BeginPaint,hWin,ADDR Ps)
    9.     invoke GetClientRect,hWin, ADDR Rct
    10.     invoke FillRect,hDC,ADDR Rct,hBrush
    11.     ;-- а здесь действия, которые могут и не выполняться, в зависимости от некоторых условий:
    12.     invoke DrawText,hDC,ADDR SomeText,-1,ADDR Rct,NULL
    13.     invoke DrawIconEx,hDC,1,1,hSomeIcon,0,0,0,0,DI_NORMAL
    14.     ;-- и здесь снова выполняемое при каждом WM_PAINT:
    15.     invoke EndPaint,hWin, ADDR Ps
    16.     ret
    17. PaintProc endp




    И когда тебе надо напечатать какой-то текст, скопируй его в буфер SomeText и вызывай InvalidateRect, при этом перерисуется окно и напечатается текст, который в буфере, если тебе надо убрать текст, забей первый байт буфера нулём, и снова InvalidateRect, окно перерисуется, но уже без текста. Вернее с текстом пустая строка.

    Ну и аналогично если надо например иконку нарисовать: в hSomeIcon либо хэндл иконки, либо ноль. Если ноль - не рисуем, если валидный хэндл - отображаем.



    Это так, схематически написано, можно дополнить и развить эту процедуру, например, указывать RECT для текста или для рисунка, может лучше сначала проверять буфер на ноль, и если ноль, то вообще не вызывать DrawIcon или DrawText, и прочие вещи
     
  6. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    San1

    Написал вот такое...

    Мой приятель делал нечто подобное для буржуйского форума. Если есть вопросы спрашывай.



    [​IMG] _609352800__demoforgallo.rar
     
  7. cresta

    cresta Active Member

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



    Если тебе по WM_MOUSEMOVE, то примерно так попробуй вызывать:


    Код (Text):
    1.     .ELSEIF uMsg==WM_MOUSEMOVE
    2.        mov eax, lParam
    3.        ;здесь определяем, где мышь
    4.        ;-
    5.        ;-
    6.        ;и если она в какой-то оговоренной области,
    7.        ;пишем текст:
    8.        invoke lstrcpy ADDR SomeText, ADDR Buffer
    9.        invoke InvalidateRect,hWnd,NULL,TRUE
    10.        ret
    11.        ;если мышь за пределами участка, и надо стереть надпись
    12.        lea eax,SomeText
    13.        mov byte ptr [eax],0
    14.        invoke InvalidateRect,hWnd,NULL,TRUE
    15.        ret




    И ещё: заведи переменную - флаг, которая будет показывать нарисован или стерт текст, чтобы при движении мыши постоянно не перерисовывать уже нарисованое, или соответственно, не стирать уже стертое. Нарисовал - забей во флаг 1, стёр - 0, и если мышь движется, проверь флаг, стерта надпись или нет, может и не надо лишний раз вызывать InvalidateRect



    Чот касается BitBlt, то где у ты получаешь hdc? Если считаешь, что по WM_CREATE получил и достаточно, то наверное это ошибочно, надо при каждом WM_PAINT делать CreateCompatibleDC. имхо.
     
  8. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    cresta

    заведи переменную - флаг ... может и не надо лишний раз вызывать InvalidateRect

    WM_PAINT приходят по разным причинам, поэтому флаг тут не помощник.



    надо при каждом WM_PAINT делать CreateCompatibleDC

    Не уверен, не пиши.
     
  9. cresta

    cresta Active Member

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







    Я не предлагаю WM_PAINT обрабатывать\не обрабатывать по флагу, а именно InvalidateRect вызывать\не вызывать в зависимости от того, надо изменить\не надо изменить







    Написал же "наверное" и в конце добавил: "имхо"
     
  10. Foamplast

    Foamplast New Member

    Публикаций:
    0
    Регистрация:
    6 ноя 2003
    Сообщения:
    80
    Адрес:
    Russia
    Блин, как у вас всё сложно.



    Я предлагаю:



    1. Все рисование происходит только в обработчке WM_PAINT

    2. Если необходимо изменить часть экрана, то используем InvalidateRect()

    3. Используем флаги для обозначения видимости элементов,

    то есть проверяем их в обработчике WM_PAINT

    4. Если происходит событие, могущее показать/спрятать элемент, то при получении такого события необходимо исследовать/изменять флаги и на основании исследования звать или не звать InvalidateRect()



    Если делать, как я предлагаю, то система сама будет следить, что нарисовано, а что надо перерисовать. Эта информация доступна из PAINTSTRUCT, как заметил cresta.
     
  11. Foamplast

    Foamplast New Member

    Публикаций:
    0
    Регистрация:
    6 ноя 2003
    Сообщения:
    80
    Адрес:
    Russia
    Если же элементов нет никаких, а надо рисовать мышью везде, где тычут, и чтоб при этом оставалось (как в PANIT), то необходимо после рисования сохранять изображения окна, а перед рисованием выводить сохранённое изображение.
     
  12. San1

    San1 New Member

    Публикаций:
    0
    Регистрация:
    3 ноя 2004
    Сообщения:
    4
    to q_q

    Огромное спасибо за исходник, очень помог. Разобрался со своими грехами. Я не верно определял размер области в памяти, да еще и hdc блока памяти засунул в локал :), поэтому Blt и ругался постояно разными ошибками.



    to cresta



    Дело в том что так как ты предлагаешь я делал. Т.е. у меня был массивчик с указанием хитпоинтов, строки символов и флага отрисовки. У этого метода есть очень большие недостатки: алгоритм запутанный, и при необходимости изменения программы в сторону утяжеления её другими отображаемыми элементами надо изрядно код поколбасить. Поэтому подумал что рисовать надо не на экране, а сразу в памяти, а по WM_PAINT отображать из памяти на экран. Вот собствено над чем и бился.



    Foamplast



    Проше сразу в памяти рисовать.
     
  13. Foamplast

    Foamplast New Member

    Публикаций:
    0
    Регистрация:
    6 ноя 2003
    Сообщения:
    80
    Адрес:
    Russia
    Ну да, так и есть.