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
.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
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?
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?
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:

The way it should look:

The way it looks now:

Resized to small looks real bad:

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
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)
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)
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.
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.
rdaneel,
If you attach (or mail) the gradients I'll try to get it worked out for you. It ain't that hard.
If you attach (or mail) the gradients I'll try to get it worked out for you. It ain't that hard.
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
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
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?
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?
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.
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.
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?
No worries. If I didn't want someone to use it, I wouldn't have posted it.
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.
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
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?
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?
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?
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?
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 :)
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 :)
haha, that is a pretty good quote, sums up about how often what I try to program actually works.
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?
*edit*
actually I just realized that f0dders original suggestion was just to make the button fonts better. any font suggestions?
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.
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.