News:

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

Change Client Area Background Color

Started by dedndave, January 09, 2011, 11:23:27 AM

Previous topic - Next topic

dedndave

i know this can be done, although - it may not be as simple as it ought to be   :(
this is basic stuff that maybe MS left out
i know Hutch's QE does it - but that may be different because it is a rich edit control
any ideas ?

during class registration, i am using this code to get a black brush (per MichaelW):
        INVOKE  GetStockObject,BLACK_BRUSH
        mov     wc.hbrBackground,eax


at the moment, i am trying NULL_BRUSH instead (which is interesting by itself - lol)
then process the WM_ERASEBKGND message - i am thinking maybe BitBlt the user-selected background color
i'll let you know how it goes   :bg

in the mean time - maybe some other member already knows a better way ?

dedndave

#1
well - i learned that setting the hbrBackground member of WNDCLASSEX to NULL will get you the WM_ERASEBKGND message
if i then process the message by returning TRUE with no fill code, it is similar to using NULL_BRUSH

now all i need is a fast way to fill the rectangle   :bg
working on it....

dedndave

well i have it up and running - it works great
but - i have a question about handling the WM_ERASEBKGND message
the msdn documentation is a little sketchy (again)

i have to figure that the erase handler may only be required to erase part of the client area
so - to find out what part, i use BeginPaint and EndPaint, just like a WM_PAINT handler
now, the BeginPaint docs say that those functions should only be used to process WM_PAINT messages
but, at the end of the WM_ERASEBKGND docs, under "Other Resources", it lists BeginPaint and PAINTSTRUCT

is it safe to assume that i am doing it the right way ?????

qWord

Why not setting wc.hbrBackground to zero and clear the background while drawing (WM_PAINT,...). On the other hand, you can use GetUpdateRect() to receive the rect, that must be update.
FPU in a trice: SmplMath
It's that simple!

dedndave

that's what i did - GetUpdateRect - with a NULL so that it doesn't send another WM_ERASEBKGND message
works great   :bg

Gunner

Quote from: dedndave on January 09, 2011, 12:52:26 PM
now all i need is a fast way to fill the rectangle   :bg
working on it....

What about ExtFloodFill or FillRect?
~Rob (Gunner)
- IE Zone Editor
- Gunners File Type Editor
http://www.gunnerinc.com

dedndave

well - i am using CreateCompatibleDC, DIB, BitBlt
it is pretty fast
although, those methods sound easier
i may have to try them out

donkey

Hi Dave,

I don't mean to sound pedantic but this seems like a lot of work for a simple task. Since you are setting wc.hbrBackground I assume that you are using a private window class. In that case changing the background color is as easy as:

invoke SetClassLong,[hwnd],GCL_HBRBACKGROUND,[hNewBrush]
; OR
invoke SetClassLong,[hwnd],GCL_HBRBACKGROUND,COLOR_BTNFACE+1
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

dedndave

nothing pedantic there, Edgar - lol
i am here to learn

and - it is a lot of code for what should be something simple
i didn't realize that i could alter the registered class

as i have it now, i am setting the wc.hbBackground to NULL
but, if i don't have to have an erase handler, that would be great
i will try it out a little later - have to go take care of dad for a while

donkey

Family comes first  :thumbu

Here's a little demo that allows you to select the color of the window when the app starts. You can actually do it any time but I didn't feel like writing the code for that so I just put the color selection in the WM_CREATE handler. Demonstrates the method though.

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

hutch--

Dave,

You try and line it up so that only one window upgrades in the client area of your main window otherwise you get flickering when you resize the window. Now in the case of where you have another control fully covering the client area you set the main window background brush to NULL so it does not keep repainting under the other control.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

dedndave

thanks Edgar - i appreciate the help

Hutch - it's a simple single-client app - lol
the problem is...
... i am a total n00b at this stuff   :bg
i feel like i have read half the msdn site, but i know i haven't even put a dent in it

hutch--

Dave,

After a while it gets better when your head stops hurting (from banging it against the wall). The basic design of how the OS creates a window is to set the class background brush in the WNDCLASSEX structure. The code that Edgar posted is how you change it later by changing the class attribute. You can blame Win32 on the old VAX guys who stuffed as much as they could into structures.

There are other ways to set the colour of the client area like sizing a rectangle set with your chosen colour but the WNDCLASSEX background brush performs a lot better.

With the class attribute each time Windows must update the display (if a window has been overlapped by another for example) it just picks the colour from the CLASS that the window was created with and fills the area that has been messed up.

LATER: Here is a simple demo on setting the client area color. I have marked the code in the WndProc so you can easily find it.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

donkey

Hi Hutch,

You can potentially run out of resources if you don't delete the brushes. The return value of SetClassLong is the old brush handle which is no longer needed. So you should think about adding a DeleteObject. Also InvalidateRect does not need a RECT if you're adding the entire client area

invoke CreateSolidBrush,0000FF00h                   ; GREEN as COLORREF number
mov hBrush, eax
invoke SetClassLong,hWin,GCL_HBRBACKGROUND,hBrush
invoke DeleteObject, eax ; <<<< Delete the old brush <<<<<<<<<<<
invoke InvalidateRect,hWin,NULL,TRUE
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

hutch--

I was trying to pass Dave a simple enough example without extra the complexity. The cleanest way to do this is as follows.

Brush handles in the .DATA? section

    .data?
      redbrush   dd ?
      greenbrush dd ?
      bluebrush  dd ?


Set the brush colors early in the code section

      mov redbrush,   rv(CreateSolidBrush,000000FFh)
      mov greenbrush, rv(CreateSolidBrush,0000FF00h)
      mov bluebrush,  rv(CreateSolidBrush,00FF0000h)


Use the brushes when you change color.

          case 2001
            invoke SetClassLong,hWin,GCL_HBRBACKGROUND,greenbrush
            invoke GetClientRect,hWin,ADDR Rct
            invoke InvalidateRect,hWin,ADDR Rct,TRUE


Ditch the brushes on exit although it does not matter there.

A test piece to test the difference between a selected object and a brush handle shows an interesting result.


            push esi
            mov esi, 1000000

          @@:
            invoke SetClassLong,hWin,GCL_HBRBACKGROUND,redbrush     ; set the class attribute
            ;;;; invoke DeleteObject,eax
            invoke GetClientRect,hWin,ADDR Rct                      ; get the client area rectangle
            invoke InvalidateRect,hWin,ADDR Rct,TRUE                ; force repaint by invalidating it

            invoke SetWindowText,hWnd,str$(esi)

            sub esi, 1
            jnz @B

            pop esi


This code will lock up the display with or without DeleteObject. The difference is with it the display is not updated after the loop finishes when you use DeleteObject() on the old brush handle. It just happens to be that the brush handle set in the WNDCLASSEX structure is not selected into a device context so there does not appear to be any purpose in trying to delete a non selected object.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php