I am so naive about GDI painting so forgive me if my code is terribly wrong.  Originally I was painting the background by just putting a really large brush in the background element of the window class I registered for the main window.  My needs have outgrown that though.  I am now trying to use a set of brushes to paint the background of my main window.  I have a brush for top-left-corner, top-right-corner, top-span, side-span, etc.  Everything I've tried leaves me with a bunch of garbled up results as the background and I just can't figure out what I'm doing wrong.  Maybe someone can look at my code and spot a glaring problem.  If the whole thing is just bad then let me know that too.  Sorry for posting so much code but I don't know where the problem is.  Here is the excerpt from my WNDPROC:


    .ELSEIF uMsg==WM_PAINT
        ; Check for an update region
        invoke  GetUpdateRect, hWnd, ADDR rect, TRUE
        .IF(eax==0)
            xor    eax, eax
            ret
        .ENDIF
        ; Setting the batch helps prevent flickering from the background erase
        invoke  GdiSetBatchLimit ,25

        ; Start the painting operation       
        invoke  BeginPaint, hWnd, ADDR ps

        ; Blit the results into the DC using SRCCOPY
        invoke  BitBlt ,ps.hdc,0,0,ps.rcPaint.right,ps.rcPaint.bottom,hDCBackgroundCopy,0,0,SRCCOPY

        ; Flush the GDI cache to finish drawing onto the control
        invoke  GdiFlush
        invoke  EndPaint, hWnd, ADDR ps
        xor    eax, eax
        ret

    .ELSEIF uMsg==WM_SIZE
        ;##: Delete the old DC and bitmap
        invoke  SelectObject, hDCBackgroundCopy, hBmpBackgroundCopy
        invoke  DeleteObject, hBmpBackgroundCopy
        invoke  ReleaseDC, hWnd, hDCBackgroundCopy
        invoke  DeleteDC, hDCBackgroundCopy     

        ; Get the size and the DC
        invoke  GetWindowRect, hWnd, ADDR rect
        invoke  CreateRoundRectRgn, rect.left, rect.top, rect.right, rect.bottom, dwMainWidth, dwMainHeight
        mov    hRegion, eax
        invoke  GetWindowRgn, hWnd, hRegion
        invoke  GetRgnBox, hRegion, ADDR rect

        ;invoke  dwtoa, rect.right, ADDR debugBuffer
        ;invoke  MessageBox, hWnd, ADDR debugBuffer, ADDR AppTitle, MB_OK
        ;invoke  dwtoa, rect.bottom, ADDR debugBuffer
        ;invoke  MessageBox, hWnd, ADDR debugBuffer, ADDR AppTitle, MB_OK       

        invoke  GetWindowDC, hWnd
        mov    hDCWin, eax
       
        ; Copy the DC and create a Bitmap for it and select it into it for drawing
        invoke  CreateCompatibleDC, hDCWin
        mov    hDCCopy, eax

        invoke  CreateCompatibleBitmap, hDCWin, rect.right, rect.bottom
        mov    hBmpCopy, eax
       
        invoke  SelectObject, hDCCopy, hBmpCopy
        mov    hBmpCopy, eax
        mov    hBmpBackgroundCopy, eax       
   
        ; Set the properties for the DC (font, text color) and fill the background to black
        ;invoke  SetBkColor, hDCCopy, 0ffeec1h
        ;invoke  CreateSolidBrush, 0ffeec1h
        ;push    eax
        ;invoke  FillRect, hDCCopy, ADDR rect, eax
        ;pop    eax
        ;invoke  DeleteObject, eax

        ; Paint the left side span
        invoke  SelectObject, hDCCopy, hBmpBkgSideL
        push    eax
        mov    eax, rect.top
        .WHILE(eax<rect.bottom)
            push    eax
            invoke  PatBlt, hDCCopy, 0, eax, 32, 2, PATCOPY
            pop    eax
            add    eax, 2
        .ENDW
        pop    eax
        invoke  SelectObject, hDCCopy, eax

        ; Paint the right side span
        invoke  SelectObject, hDCCopy, hBmpBkgSideR
        push    eax
        mov    edx, rect.right
        sub    edx, 32
        mov    eax, rect.top
        .WHILE(eax<rect.bottom)
            push    eax
            push    edx
            invoke  PatBlt, hDCCopy, edx, eax, 32, 2, PATCOPY
            pop    edx
            pop    eax
            add    eax, 2
        .ENDW
        pop    eax
        invoke  SelectObject, hDCCopy, eax

        ; Paint the top span
        invoke  SelectObject, hDCCopy, hBmpBkgTop
        push    eax
        mov    eax, rect.left
        .WHILE(eax<rect.right)
            push    eax
            invoke  PatBlt, hDCCopy, eax, 0, 2, 32, PATCOPY
            pop    eax
            add    eax, 2
        .ENDW
        pop    eax
        invoke  SelectObject, hDCCopy, eax

        ; Paint the bottom span
        invoke  SelectObject, hDCCopy, hBmpBkgBot
        push    eax
        mov    edx, rect.bottom
        sub    edx, 32
        mov    eax, rect.left
        .WHILE(eax<rect.right)
            push    eax
            push    edx
            invoke  PatBlt, hDCCopy, eax, edx, 2, 32, PATCOPY
            pop    edx
            pop    eax
            add    eax, 2
        .ENDW
        pop    eax
        invoke  SelectObject, hDCCopy, eax               
       
        ; Paint the top-left corner
        invoke  SelectObject, hDCCopy, hBmpBkgCornerTL
        push    eax
        invoke  PatBlt, hDCCopy, 0, 0, 32, 32, PATCOPY
        pop    eax
        invoke  SelectObject, hDCCopy, eax

        ; Paint the top-right corner
        invoke  SelectObject, hDCCopy, hBmpBkgCornerTR
        push    eax
        mov    eax, rect.right
        sub    eax, 32
        invoke  PatBlt, hDCCopy, eax, 0, 32, 32, PATCOPY
        pop    eax
        invoke  SelectObject, hDCCopy, eax

        ; Paint the bottom-left corner
        invoke  SelectObject, hDCCopy, hBmpBkgCornerBL
        push    eax
        mov    eax, rect.bottom
        sub    eax, 32
        invoke  PatBlt, hDCCopy, 0, eax, 32, 32, PATCOPY
        pop    eax
        invoke  SelectObject, hDCCopy, eax

        ; Paint the top-right corner
        invoke  SelectObject, hDCCopy, hBmpBkgCornerBR
        push    eax
        mov    eax, rect.right
        sub    eax, 32
        mov    edx, rect.bottom
        sub    edx, 32
        invoke  PatBlt, hDCCopy, eax, edx, 32, 32, PATCOPY
        pop    eax
        invoke  SelectObject, hDCCopy, eax               

        push    hDCCopy
        pop    hDCBackgroundCopy

        invoke  ReleaseDC ,hWnd,hDCWin
        xor    eax, eax
        ret   

    .ELSEIF uMsg==WM_ERASEBKGND
        ; Get the size and the DC
        invoke  GetWindowRect, hWnd, ADDR rect
        mov    eax, rect.right
        sub    eax, rect.left
        mov    rect.right, eax
        mov    eax, rect.bottom
        sub    eax, rect.top
        mov    rect.bottom, eax       
        mov    rect.top, 0
        mov    rect.left, 0

           
        ; Set the properties for the DC (font, text color) and fill the background to black
        invoke  SetBkColor, wParam, 0ffeec1h
        invoke  CreateSolidBrush, 0ffeec1h
        push    eax
        invoke  FillRect, wParam, ADDR rect, eax
        pop    eax
        invoke  DeleteObject, eax
           
        mov    eax, 1
        ret
Posted on 2006-06-16 17:35:26 by rdaneel
Hi rdaneel,

I had a quick look at your code and I think I know what you're doing - but - to not confuse you with (wrong) assumptions could you describe what exactly you like to achieve?

If I am not mistaken you only paint something on the DC besides painting it black on EraseBackground is during a WM_Size message. Is that how you want it? Is there other code painting those 4 corners somewhere else?
Posted on 2006-06-16 18:25:20 by JimmyClif
That's close.  What I am wanting to do is hold a buffer of the assembled background image and then blt from that buffer onto the hdc whenever a WM_PAINT is called.  Since the window is resizable I just create the newly assembled background bmp once per WM_SIZE message and blt off of it during WM_PAINT.  There are child controls on the window so I figured that assembling the complete background in a buffer and blt'ing it into the clipped DC that BeginPaint returns was the only way to keep everything sane.  It sounded like a good plan in my mind but if you know of a better way I'd love to hear it.  Here are a couple of screen shots if it will clarify.  It looks almost good but when the window resizes it gets worse.

The way it should look:


The way it looks now:


Resized to small looks real bad:
Posted on 2006-06-16 18:59:27 by rdaneel
Without trying anything it looks to me like your code is 1 pixel off that's where the black line comes in. You should prevent your window to be able to get resized smaller than at least 64 x 64 due to the 4 corners you paint.

But here's my scoop on the deal

You can cut out a lot of baloney (Api calls) when you do the following:

First add these two procs to your repertoire


;========================================================================
;                          GetBitmapDC
;========================================================================
;  Usage:
;  invoke GetBitmapDC, ADDR BitmapDC, ADDR NameOfBitmap, ADDR hBitmap, hwnd
;This is used to create DC's for Bitmaps. Just pass :
;BitmapDC a dword - which will receive the DC you'll be working with later on.
;NameOfBitmap - the name of the Bitmap to take into the DC.
;HandleOfBitmap - an empty dword which will receive the handle of the Bitmap.
;Do not forget to DeleteDC and DeleteObject for the created Handle and DC at program exit.
;========================================================================
GetBitmapDC proc AnotherDC:DWORD, BitmapADDR:DWORD,HandleOfBitmap:DWORD, hwnd:DWORD
    invoke GetDC,hwnd
    push eax            ;1 push DC for release later
    invoke CreateCompatibleDC,eax
    mov edx,AnotherDC
    push eax            ;2 push DC for SelectObject
    mov ,eax
    invoke LoadBitmap,hInstance,BitmapADDR
    mov edx,HandleOfBitmap
    pop ecx                ;2 pop Created DC
    mov ,eax
    invoke SelectObject,ecx,eax
    pop eax                ;1 pop DC to release
    invoke ReleaseDC,hwnd,eax
ret
GetBitmapDC endp

;========================================================================
;                          GetCompatibleBitmap
;========================================================================
;  Usage:
;  invoke GetCompatibleDC, ADDR ImageDC, ADDR hImageDC, hwnd, 500, 300
; This little function is used to create DC for BackBuffers, Images and so on.
; All there is to do is pass 2 dwords which will hold the DC (the one you'll be painting on)
; and the handleDC which both need to be deleted at program exit (with DeleteDC and DeleteObject)
;========================================================================
GetCompatibleBitmap proc AnotherDC:DWORD, HandleOfDC:DWORD, hwnd:DWORD, xLenght:DWORD, yWidth:DWORD
    invoke CreateCompatibleDC,NULL
    mov edx,AnotherDC
    push eax
    mov ,eax
    invoke GetDC,hwnd
    push eax
    invoke CreateCompatibleBitmap,eax,xLenght,yWidth
    mov edx,HandleOfDC
    mov ecx,        ;pop ecx
    mov ,eax        ;push eax
    mov ,eax
    invoke ReleaseDC,hwnd,ecx
    pop eax                ;HandleOfDC
    pop ecx                ;AnotherDC
    invoke SelectObject,ecx,eax
    ret
GetCompatibleBitmap endp

Load all your Bitmaps using GetBitmapDC inside your WM_CREATE handler and create a BackBufferDC there too.
Now on Resize, Destroy your old BackBufferDC and create a new one.
You can paint it there or move it inside your WM_PAINT handler. Anyway, paint it the way you like it. You can drop every call to SelectObject and all you need to do is BitBlt the BitmapDC's onto the BackBufferDC. Inside WM_PAINT all you need to do is BitBlt the BackBuffer onto the ps.hdc.

I attach a little test of mine to it so that you can see on how easy my way would be. I tried to whop up a gradient test for you but my wife is going to crucify me if I spend anymore time painting gradients here. (Note: In my example I did not use a Backbuffer)
Attachments:
Posted on 2006-06-16 21:13:30 by JimmyClif
Thankyou so much.  I will try this all out tommorrow and post back any interesting results.  For some reason I have always had a mental block against GDI stuff.  I just can't seem to "get it".  Ditto the wife thing.  Thanks again JimmyClif. 
Posted on 2006-06-17 00:32:18 by rdaneel
If you're going to use a backbuffer and resize on WM_SIZE etc., you might want to consider resizing in increments - otherwise you might get a *lot* of resizes.
Posted on 2006-06-17 06:07:17 by f0dder
rdaneel,

If you attach (or mail) the gradients I'll try to get it worked out for you. It ain't that hard.
Posted on 2006-06-17 10:25:28 by JimmyClif
Here's my little test. I believe your gradient bitmaps are a lot better than my quick thrown together bunch.

Also, it is not recommended to have this many calls loading each Bitmap, but it would be wiser creating one bigger bitmap having them all and then just selecting the part you need for blitting.

Anyways, hope this helps.

Removed attachment
Posted on 2006-06-17 12:41:33 by JimmyClif
f0dder: It actually only has 2 sizes.  It has a small systray progress popup thingy and a bigger management interface.  I'm using the same window and just hiding and showing controls on it.  You can download the app at http://www.sector62.com/cgi-bin/pl.cgi/software/podwrangler.html to see what I mean.

JimmyClif: I'm going to attach the graphics in a zip to this post.  I haven't looked at your stuff yet since I have been busy with work but I plan on it tonight when I get home.  I seem to remember reading in the API docs that some of the Blt functions skip that last or first pixel row.  Could that be a source of my 1 pixel mismatch?
Posted on 2006-06-17 16:45:22 by rdaneel
Hi rdaneel,

That was fun :) I just replaced your bitmaps with my code and voila here's the finished product. ~ Well almost. There is lots of room for improvement but it kinda does what you want.
Attachments:
Posted on 2006-06-17 17:39:32 by JimmyClif
Beautiful work JimmyClif.  I like your solution better.  Now that I see a working solution it makes so much more sense.  I think PatBlt was screwing me up too.  That one GetBitmapDC function made it cleaner.  Can I use that function and credit you in my code?
Posted on 2006-06-18 08:38:47 by rdaneel
No worries. If I didn't want someone to use it, I wouldn't have posted it.
Posted on 2006-06-18 08:53:09 by JimmyClif
I merged the code into mine in the appropriate way and it came out wonderful.  I was able to cut my filesize way down by using the chopped up bitmap sections instead of the class brush.  If you want to see the finished product you can grab it at my site: http://www.sector62.com.  The program is called PodWrangler.  Thanks again.
Posted on 2006-06-19 13:04:29 by rdaneel
I finally got around to posting the source for this program.  I didn't want to post it until I put in safer string handling than just plain ol' lstr___ functions.  Maybe someone will find this code useful since it brings together a bunch of different stuff I've picked up from this forum over the years, not to mention the GDI stuff talked about here.  I used the Windows HTTP functions rather than coding my own HTTP engine this time around.  I did that once before with asynchronous sockets and the whole sh'bang and I have to say that it was painful.  Oh well, here is the link to the source and the binary versions: http://www.sector62.com/cgi-bin/pl.cgi/software/podwrangler.html
Posted on 2006-06-29 16:34:46 by rdaneel
Looks pretty decent :)

A couple of suggestions... don't exit the app when you Alt+F4 the "manage list" window, just function like when pressing "hide" instead.

Also, since the app is visual, what about setting a more pleasing font on the buttons?
Posted on 2006-07-03 12:30:24 by f0dder
Good ideas.  For that matter, the buttons should probably be graphical too instead of just regular Windows push buttons.  Well here comes another night that my wife will hate me.  ;)

In your opinion is it better to use owner-drawn buttons, subclass the buttons for painting or use GDI regions+hit testing as buttons?  What gives the best balance between flexibility and complexity?
Posted on 2006-07-03 16:51:48 by rdaneel
SubClassing is probably the easiest and most flexible. You can paint a button on WM_PAINT and create effects on WM_MOUSEMOVE, WM_LBUTTONDOWN and WM_LBUTTONUP simulating a regular Button.

Ewayne has made a little Button demo displaying a lot of styles on can have. Check them out at: http://spiff.tripnet.se/~iczelion/files/Buttons.zip

BTW: I really like this line from your About Me page:


I like writing software that is small, fast and very useful and every few hundred tries I manage to actually do that.


So true :)
Posted on 2006-07-03 18:30:42 by JimmyClif
haha, that is a pretty good quote, sums up about how often what I try to program actually works.
Posted on 2006-07-03 20:04:09 by Bobbias
I finally got around to making PodWrangler's buttons pretty like f0dder suggested.  I posted the new source on my site if anyone is wanting to do something similar.  It's too big to post here.  I might not have done it the most efficient way (superclassing along with a thousand nearly identical variable names) but it seems pretty solid.  The most important thing is that just like the window background, I can now just drop in any bitmaps and they will expand and contract correctly.  I put in bitmaps for hover, up, and down button states.  If there is a better way to do it I'd like to know.

*edit*
actually I just realized that f0dders original suggestion was just to make the button fonts better.  any font suggestions?
Posted on 2006-07-27 16:29:17 by rdaneel
Nifty! :)


I might not have done it the most efficient way (superclassing along with a thousand nearly identical variable names) but it seems pretty solid.

If you need a variable per control you superclass, you should consider SetProp() and store your variable there (if you need multiple variables per control, HeapAlloc() a structure and store the pointer instead).


actually I just realized that f0dders original suggestion was just to make the button fonts better. ? any font suggestions?

The one windows uses by default on DIALOGs would be decent enough; can't remember which font it is, but iirc there's a way to specify the "system default dialog font" or something like that.
Posted on 2006-07-28 06:35:41 by f0dder