News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

WM_PAINT & InvalidateRect

Started by hotrod, January 23, 2010, 01:28:35 AM

Previous topic - Next topic

hotrod

This code will draw a rectangle each time the button is pressed, but only the last one is left if the window loses focus. I know that WM_PAINT accumulates requests before painting and does it all in one pass. What is the work around for this problem? Thanks...


.elseif uMsg==WM_COMMAND
.if wParam==1001 ; Button
mov hBG_Brush, rv(CreateSolidBrush, colRed)
add RT.left, 31
add RT.right, 30
invoke InvalidateRect, hWin, addr RT, FALSE
.endif
ret
.elseif uMsg==WM_PAINT
mov hDC, rv(BeginPaint, hWin, addr PS)
invoke FillRect, hDC, addr RT, hBG_Brush
invoke EndPaint, hWin, addr PS
ret

MichaelW

One workaround would be to draw the rectangles on a bitmap, and after each one is drawn copy the entire bitmap to the client area of the window. The attachment contains an example.
eschew obfuscation

hotrod

Thanks MichaelW, there is a lot of info in the example and will keep me busy for a couple of days; I really appreciate all the comments. What is causing the deletion of the previous object if (invoke InvalidateRect, hWin, addr RT, FALSE) bErase is set to false? I would normally say that the entire window is being repainted, but that can't be true if the previous object is still visible when the new one is added.

I have also notice this same issue with control (statics, edits) backgrounds which makes it a little more complicated in that using this approach, the static would loose its attributes such as SetDlgItemInt since it is being translated to a bitmap. Is there another solution?

Am I correct in saying that redrawing the entire window, which takes processing time, is the answer to both issues so graphics and controls can coexist or am I off in left field?

MichaelW

The previous rectangles remain visible only until the client area background is erased. The current rectangle is visible after the background is erased because your WM_PAINT handler is redrawing it. The attachment contains a test app that I hope illustrates what is happening.

Child controls in a window, including the static controls, are redrawn automatically.
eschew obfuscation

Tight_Coder_Ex

Actually InvalidateRect, all it does is accumulates areas that will need updating.  If you want the button press to respond each time add invoke   UpdateWindow, hWin and then WM_PAINT is forced to respond to each button press
Do this immediately after InvalidateRect

hotrod

Hello Tight_Coder_Ex and thanks, but the issue is still there. I think I tried your suggestion before, but I have done so many that I can't remember them all. If you have a working example, I would appreciate it.



.elseif uMsg==WM_COMMAND
.if wParam==1001 ; Button
mov hBG_Brush, rv(CreateSolidBrush, colRed)
add RT.left, 31
add RT.right, 30
invoke InvalidateRect, hWin, addr RT, FALSE
invoke UpdateWindow, hWin    ; Your code
.endif
ret

Tight_Coder_Ex

Maybe send me a copy of the entire application and I may be able to spot something that is not even in the area we are looking at

hotrod

Here you go and thanks.

qWord

maybe a global mem-DC is the right for your task:
WndProc proc    hWin:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL PS    :PAINTSTRUCT
LOCAL hDC   :HDC
LOCAL nx    :DWORD
LOCAL ny    :DWORD

    SWITCH uMsg
        CASE WM_CREATE
            push hWin
            pop hMain

            invoke CreateWindowEx, WS_EX_CLIENTEDGE, SADD("BUTTON"), SADD("MAKE RECT"),WS_CHILD + BS_PUSHBUTTON + WS_VISIBLE, 50, 100, 50, 25, hWin, 1001, hInstance, NULL

            .data
                hMemDC  dd ?                            ; global DC , back-buffer
                RT      RECT <10-30, 10, 30-30, 30>     ; new start-value: -20,10,0,30
            .code

            mov hDC,rv(GetDC,0) ; get Desktop-DC
            mov hMemDC,rv(CreateCompatibleDC,eax)                                               ; create MemDC

            mov nx,rv(GetSystemMetrics,SM_CXSCREEN)                                             ; use screen size for MemDC
            mov ny,rv(GetSystemMetrics,SM_CYSCREEN)                                             ;
            invoke DeleteObject,rv(SelectObject,hMemDC,rv(CreateCompatibleBitmap,hDC,nx,ny))    ;
            invoke ReleaseDC,0,hDC

            invoke DeleteObject,rv(SelectObject,hMemDC,rv(CreateSolidBrush,0ffffffh))           ; Fill memory DC with white color
            invoke DeleteObject,rv(SelectObject,hMemDC,rv(CreatePen,PS_SOLID,1,0ffffffh))       ;
            invoke Rectangle,hMemDC,0,0,nx,ny                                                   ;

            invoke DeleteObject,rv(SelectObject,hMemDC,rv(CreateSolidBrush,colRed))             ; select brush = red
            invoke DeleteObject,rv(SelectObject,hMemDC,rv(CreatePen,PS_SOLID,1,colRed))         ; select pen   = red

        CASE WM_COMMAND
            .if wParam==1001    ; Button

                add RT.left, 30
                add RT.right,30

                .if RT.right > 300  ; some limit for 'line break'
                    mov RT.left,10
                    mov RT.right,30
                    add RT.top,30
                    add RT.bottom,30
                .endif
                invoke Rectangle,hMemDC,RT.left,RT.top,RT.right,RT.bottom   ; draw rectangle in hMemDC using current brush and pen (color=red)
                invoke InvalidateRect,hWin,ADDR RT,FALSE                    ; invalidate drawn rectangle
            .endif
            ret
        CASE WM_PAINT
            mov hDC, rv(BeginPaint, hWin, addr PS)

            ; copy only what needed to screen
            mov eax,PS.rcPaint.left
            sub PS.rcPaint.right,eax
            mov edx,PS.rcPaint.top
            sub PS.rcPaint.bottom,edx
            invoke BitBlt,hDC,PS.rcPaint.left,PS.rcPaint.top,PS.rcPaint.right,PS.rcPaint.bottom,hMemDC,PS.rcPaint.left,PS.rcPaint.top,SRCCOPY

            invoke EndPaint, hWin, addr PS
            ret
        CASE WM_DESTROY
            invoke PostQuitMessage, NULL

        DEFAULT
            invoke DefWindowProc, hWin, uMsg, wParam, lParam
            ret
    ENDSW

    xor eax, eax
    ret
WndProc endp
FPU in a trice: SmplMath
It's that simple!

hotrod

Works for me qWord. This is very similar to what I got from MichaelW for a BitBlt problem I was having. It seems that back buffering is the ideal way controlling the normal processing of Window's events for graphics and has given me a large boost. I think they should have made WM_ERASEBKGND more user friendly instead of embedding it. I have seen more references to it by users trying to program graphics than any other single issue.

Tight_Coder_Ex

CS_SAVEBITS eliminated the problem of erasure when moving the border, so long as the border wasn't resized to be smaller or cover existing rectangles

Solution, by either a compatible DC such as would be used for scrolling or an array of values so the entire set of rectangles could be recreated in thier original positions.

hotrod

Thanks Tight_Coder_Ex, I think it is working now. I have BitBlt as provided by qWord (above) and MichaelW (earlier BitBlt post) along with the array that I came up with.

xandaz

   Can someone tell me why the rectangle doesnt clear?


.code
...
invoke GetClientRect,hStatic,addr rect
invoke InvalidateRect,hStatic,addr rect,TRUE
invoke SendMessage,hStatic,WM_SETTEXT,NULL,addr MyString


Antariy

Try this:


.code
...
invoke GetClientRect,hStatic,addr rect
invoke RedrawWindow,hStatic,addr rect,0,RDW_ERASE or RDW_INVALIDATE or RDW_ERASENOW ; <--- THIS
invoke SendMessage,hStatic,WM_SETTEXT,NULL,addr MyString


xandaz

   Thanks Antary but it doesn't work wither. ty