News:

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

Graphics, Coordinate systems, etc. questions

Started by Jimg, May 07, 2007, 04:53:49 PM

Previous topic - Next topic

Jimg

Ok, dumb question #436-

I'm confused as to what I am supposed to do when I get a WM_DRAWITEM as opposed to getting a WM_PAINT message.  What parts are supposed to be done where, or can I do it all in one or the other?

I understand I also have to do redrawing on WM_RESIZE.  What other messages require redrawing of some kind?

Jimg

#16
So I wrote a simple logger (prtmsg2) to write out the value of every message I get in my lpfnWndProc that handles all the message to my control.
I wrote an app that has one instance of the control and nothing else.
I ran the app to see what message the control was getting.
The lpfnWndProc looks like this-
GridUProc Proc hCtrl:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
inv prtmsg2,uMsg,0 ;   this prints out the message to a log file
mov eax,uMsg
.if eax==WM_CREATE
.elseif eax==WM_DRAWITEM
.elseif eax==WM_PAINT
.elseif eax==WM_ERASEBKGND
.elseif eax==WM_SIZE
.elseif eax==WM_GETDLGCODE
.elseif eax==WM_DESTROY
.elseif eax==WM_SETFOCUS
.elseif eax==WM_VSCROLL
.elseif eax==WM_HSCROLL
.elseif eax==WM_MOUSEWHEEL
.else
Invoke DefWindowProc,hCtrl,uMsg,wParam,lParam
jmp GridURet
.endIf
GridUProcExit:
xor eax,eax
GridURet:
ret

GridUProc EndP

I started the test app and immediately closed it.
This is what I got-
WM_NCCREATE=129
WM_NCCALCSIZE=131
WM_CREATE=1
WM_SIZE=5
WM_MOVE=3
WM_SHOWWINDOW=24
WM_SETFONT=48
WM_GETDLGCODE=135
unknown=1025
WM_GETDLGCODE=135
WM_SETFOCUS=7
WM_PAINT=15
WM_NCPAINT=133
WM_ERASEBKGND=20
WM_PAINT=15
WM_PAINT=15
WM_PAINT=15
WM_PAINT=15
.
.
.
.        over 300 thousand more WM_PAINT messages
.
.
WM_PAINT=15
WM_KILLFOCUS=8
WM_DESTROY=2
WM_NCDESTROY=130

I never saw a WM_DRAWITEM message.
What's with all these paint messages?
edit:  ugly test program upload deleted

ramguru

Hi, Jimg
WM_DRAWITEM is only used for sub-classed owner drawn controls. I guess you're writing your grid control from scratch, so everything should be painted during WM_PAINT message. Now regarding a wave of WM_PAINT message, set WS_CLIBSIBLINGS+WS_CLIPCHILDREN to your GridU control and see the difference. Even scintilla should be created using these styles...

Jimg

Thanks for the response.
I tried add the style WS_CLIBSIBLINGS+WS_CLIPCHILDREN to the usercontrol in the test program and got the exact same thing.  And even if it had worked, I wouldn't want to count on the user to set these properly.  There is nothing similar to set in the WNDCLASSEX structure, and I don't know where else I could make these settings.
Clearly I still do not have a grasp on all these windows messages.
And I'm rather surprised about WM_DRAWITEM.



MichaelW

Quote from: ramguru on May 13, 2007, 07:32:26 PM
Now regarding a wave of WM_PAINT message, set WS_CLIBSIBLINGS+WS_CLIPCHILDREN to your GridU control and see the difference. Even scintilla should be created using these styles...
I'm sure that you meant WS_CLIPSIBLINGS, and thanks for this information. I knew about WS_CLIPCHILDREN, but adding WS_CLIPSIBLINGS cured a problem I had been having with a Scintilla control flashing intermittently when it was resized. I had given up on solving the problem.
eschew obfuscation

ramguru

OK maybe it's not related with those styles, it's very unusuall and hard to reproduce. But final investigation shows that the wave of WM_PAINT messages was to do with the same WM_PAINT implementation:
instead of
   .elseif eax==WM_PAINT
write
   .elseif eax==WM_PAINT
      invoke BeginPaint, hCtrl, ADDR pt
      
      invoke EndPaint, hCtrl, ADDR pt
And it's cured

Jimg

Excellent.  Thank you very much.

So much to learn.... :boohoo:

Jimg

After a great deal of getting other code out of the way, I'm finally at a point where I can start testing some of this graphics stuff.

Before I go to a lot of trouble saving the stuff in every CreateCompatibleDC I create, just so I can put them back before deleting the DC I created, is it possible to just delete the old bitmap, brush, etc when I select a new one into the DC and let the system delete the new selected objects when I do a DeleteDC? I mean, I know I can do it, but memory leaks are such an arcane subject when it come to graphics for me, I thought I had better ask.

Tedd

If the brush/pen/bitmap isn't selected into any DC then you can safely delete it. The defaults are usually stock-objects, but you can safely delete these too (it actually has no effect.)
However, anything you create and select into a DC, you should equally select 'out' and delete once you've finished. (DeleteDC may be good and delete its current state objects - on newer windows version - but I wouldn't rely on it.)
No snowflake in an avalanche feels responsible.

Jimg

Thank you Tedd-

The only confusing part is  "you should equally select 'out' and delete once you've finished"

How do I select out a bitmap or brush or pen from a DC without selecting a new one into it?  I can't seem to find that API.  Or is this the real and only reason for keeping the originals?  I could see selecting in a stock object for the pen and brush, but what about the bitmap?  Or does it matter?

And what really happens when a program closes.  Surely Windows keeps track of all this stuff and cleans up, no?

Jimg

Another confusing part---

I create a bitmap and select it into the DC.

But then I never reference the handle of the bitmap.  All the drawing functions that require handles want the handle of the DC, not the bitmap, right?  Including bitblt?  Do I ever use the handle of the bitmap for anything other than selecting into the DC and deleting the bitmap later?

u

Quote from: Jimg on May 23, 2007, 07:19:13 PM
Do I ever use the handle of the bitmap for anything other than selecting into the DC and deleting the bitmap later?
Not really.
Please use a smaller graphic in your signature.

Tedd

Actually, for bitmaps it's best to delete the DC and then the bitmap (in that order.)
And yeah, that's generally the reason for keeping the old ones (the comments for SelectObject say to select back in what you got out after you're done.) It is a bit of a hassle ::)
Yes, windows 'should' keep track of it, and I think it's generally done, but there were situations in past versions where gdi objects weren't kept track of properely. Just as with file handles, it's more about safety and good practice. (What 'should' happen, and what actually does happen aren't always the same.)
No snowflake in an avalanche feels responsible.

Jimg

Ok, let's see if I got all the straight----


.if uMsg==WM_CREATE
    mov eax,hCurGrid  ; handle to the current control
    inv GetDC,eax     ; get the DC of the control
    mov mctrlhDC,eax  ; save the current DC handle forever, it will never change
    inv CreateCompatibleDC,mctrlhDC   ; create a DC compatible with the controls DC
    mov mhDC,eax                      ; save the dc forever, it will never change
   
    inv GetClientRect,hCurGrid,addr tRect       ; get the size needed for the bitmap
    m2m mctrlWidth,tRect.right
    m2m mctrlHeight,tRect.bottom

    inv CreateCompatibleBitmap,mctrlhDC, mctrlWidth, mctrlHeight
    mov mhBmp,eax
    inv SelectObject, mhDC, mhBmp
    mov mhBmpOld,eax    ;  ?? to put back when the program is closing before DeleteDC ???
   
    inv SelectObject,mhDC,mhPen   ; the pen I want
    mov hPenOld,eax
    inv SelectObject,mhDC,mhBrush  ; the brush I want
    mov mhBrushOld,eax

.elseif uMsg==WM_SIZE       ; this shouldn't be happening very often, I hope

    movzx eax,word ptr lParam       ; get the new size of the control to make a new bitmap
    mov mctrlWidth,eax
    movzx eax,word ptr [lParam+2]
    mov mctrlHeight,eax
    inv SelectObject,mhDC,mhBmpOld  ; put the old one back
    inv DeleteObject,mhBmp          ; delete the current one
    inv CreateCompatibleBitmap,mctrlhDC, mctrlWidth, mctrlHeight    ; make a new one of the appropriate size
    mov mhBmp,eax                   ; and associate it with the hidden buffer
    inv SelectObject, mhDC, mhBmp
    mov mhBmpOld,eax

.elseif uMsg==WM_DESTROY
    inv SelectObject,mhDC,mhBmpOld     
    inv SelectObject,mhDC,hPenOld
    inv SelectObject,mhDC,mhBrushOld
    inv DeleteDC,mhDC                       ; should this be DeleteObject instead???
       
    inv DeleteObject,mhPen
    inv DeleteObject,mhBrush
    inv DeleteObject,mhBmp
.endif 
   
;.
;.
;.
    ; in drawing routne  e.g.

    inv DrawText, mhDC, sText, SLen,addr rectClipping, TextAlignment
    inv MoveToEx,mhDC, X1, Y1,addr lpPoint
    inv LineTo,mhDC,X2,Y2
    inv FillRect,mhDC,addr lpRect,mhBrush
    inv DrawFrameControl,mhDC,addr lpRect,DFC_SCROLL,DFCS_SCROLLLEFT
    inv BitBlt,mctrlhDC, X1, Y1, mctrlWidth, mctrlHeight, mhDC, 0, 0, SRCCOPY  ; copy directly to parent screen


Tedd

my changes/comments as ;**


.if uMsg==WM_CREATE
    mov eax,hCurGrid  ; handle to the current control
    inv GetDC,eax     ; get the DC of the control
    mov mctrlhDC,eax  ;** you should release a DC you didn't create once you've finished with it - they can change!
    inv CreateCompatibleDC,mctrlhDC   ; create a DC compatible with the controls DC
    mov mhDC,eax                      ; save the dc forever, it will never change
   
    inv GetClientRect,hCurGrid,addr tRect       ; get the size needed for the bitmap
    m2m mctrlWidth,tRect.right
    m2m mctrlHeight,tRect.bottom

    inv CreateCompatibleBitmap,mctrlhDC, mctrlWidth, mctrlHeight
    mov mhBmp,eax
    inv SelectObject, mhDC, mhBmp
    ;** there isn't initially a bitmap associated with a DC, not that it ever 'owns' a bitmap anyway
    ;** it just uses it to size itself (which is why it's your responsibility to delete it)
    ;mov mhBmpOld,eax    ;  ?? to put back when the program is closing before DeleteDC ???

    inv ReleaseDC, hCurGrid,mctrlhDC   ;** release that DC
   
    ;** if 'mhPen' and 'mhBrush' are stock objects then you don't need to worry about saving the old ones
    ;** (or deleting them) - otherwise, yes, you do
    inv SelectObject,mhDC,mhPen   ; the pen I want
    mov hPenOld,eax
    inv SelectObject,mhDC,mhBrush  ; the brush I want
    mov mhBrushOld,eax

.elseif uMsg==WM_SIZE       ; this shouldn't be happening very often, I hope

    ;** this happens first when your window is shown (after wm_create)
    ;** might be a better opportunity for creating the bitmap?
    ;** (deleting the 'old' inital one, when there wasn't one, shouldn't do any harm)

    mov eax,lParam  ;**
    mov edx,eax     ;**
    and eax,0ffffh  ;** width
    shr edx,16      ;** height
    ;movzx eax,word ptr lParam       ; get the new size of the control to make a new bitmap
    mov mctrlWidth,eax
    ;movzx eax,word ptr [lParam+2]
    mov mctrlHeight,edx ;*

    ;** seems like a long way to do it - create the new one, select it in, then delete the old one that's returned
    ;inv SelectObject,mhDC,mhBmpOld  ; put the old one back
    ;inv DeleteObject,mhBmp          ; delete the current one
    inv GetDC,hCurGrid  ;**
    mov mctrlhDC,eax    ;**
    inv CreateCompatibleBitmap, mctrlhDC,mctrlWidth,mctrlHeight    ; make a new one of the appropriate size
    mov mhBmp,eax
    inv SelectObject, mhDC, mhBmp    ; and associate it with the hidden buffer
    ;mov mhBmpOld,eax
    invoke DeleteObject, eax    ;** delete the old bitmap (as returned from selecting the new one in)

    inv ReleaseDC, hCurGrid,mctrlhDC     ;**

.elseif uMsg==WM_DESTROY
    ;inv SelectObject,mhDC,mhBmpOld     ;** no need (and we don't have it)
    inv SelectObject,mhDC,hPenOld
    inv SelectObject,mhDC,mhBrushOld
    inv DeleteDC,mhDC                       ; should this be DeleteObject instead??? ** no, DeleteDC is right **
       
    inv DeleteObject,mhPen
    inv DeleteObject,mhBrush
    inv DeleteObject,mhBmp
.endif
   
;.
;.
;.
    ; in drawing routne  e.g.

    inv DrawText, mhDC, sText, SLen,addr rectClipping, TextAlignment
    inv MoveToEx,mhDC, X1, Y1,addr lpPoint
    inv LineTo,mhDC,X2,Y2
    inv FillRect,mhDC,addr lpRect,mhBrush
    inv DrawFrameControl,mhDC,addr lpRect,DFC_SCROLL,DFCS_SCROLLLEFT
    ;** it's our good friend GetDC again ;)
    ;** unless this is in wm_paint, and then BeginPaint returns the correct one anyway
    ;** (either way, you shouldn't be using mctrlhDC)
    inv BitBlt,mctrlhDC, X1, Y1, mctrlWidth, mctrlHeight, mhDC, 0, 0, SRCCOPY  ; copy directly to parent screen
No snowflake in an avalanche feels responsible.