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
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.
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?
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.
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
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
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
Here you go and thanks.
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
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.
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.
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.
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
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
Thanks Antary but it doesn't work wither. ty
If use:
invoke RedrawWindow,hStatic,addr rect,0,RDW_ERASE or RDW_INVALIDATE or RDW_UPDATENOW ; UPDATENOW instead
This should force repainting.
It appears that you are using a static and trying to clear the text. If so, use an empty string:
QuoteMyString equ "",0
invoke SendMessage,hStatic,WM_SETTEXT,NULL,addr MyString
It crossed my mind hotrod but clearing it seems more better. thanks antariy.
oh yeah btw. It clears the area if i use NULL for window handle when using invalidaterect, but, the whole screen gets updated or something. It's strange.
Not working antariy..Anyone else want to give it a try?
Thanks for th helpingness.
Quote from: xandaz on November 20, 2010, 12:36:36 AM
oh yeah btw. It clears the area if i use NULL for window handle when using invalidaterect, but, the whole screen gets updated or something. It's strange.
NULL (0) is a handle of desktop - i.e. entire screen. You are repainting all screen then.
My suggestions is followed your code. But you can set new text to static without manual redrawing of it. If you do not use special styles like transparency - this will work fine.
So, instead of:
.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
Just:
.code
...
invoke SendMessage,hStatic,WM_SETTEXT,NULL,addr MyString
There's no transparency i think, and dont get me wrong cause i appreciate the help. The thing is that i'm going to display the current directory. if the previous string is longer than the current it will show parts of the previous. Thanks
xandaz, you are trying to clear a control by using graphics and I don't think you are not going to be able to isolate the static from the rest of the window. The other possibility is to DrawText on the window and not use a static. You can then clear it with a rectangle.
Your answer seems satisfying enough. i quit. ill use a string.