News:

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

Child window not appearing at first

Started by NoCforMe, November 13, 2011, 05:44:57 AM

Previous topic - Next topic

drizz

Quote from: dedndave on November 13, 2011, 11:12:50 PM
it's also important to note that i use the main window handle from the WndProc parm, not the global value
the global handle variable has not yet been initialized when WM_CREATE is handled   :P
It's probably this...
CreateWindow sends messages to wndproc before it returns with the handle.
The truth cannot be learned ... it can only be recognized.

dedndave

that's correct   :U

i could have done a little better job on the WM_SIZE code
wParam tells you if it is a minimized window - no need to size the child if minimized
also, lParam low/high have the client width and height
i used GetClientRect - an unnecessary step
but, you get the idea

NoCforMe

Thanks, Dave. Haven't had a chance yet to look at what you posted but I will later.

I fixed the problem by sidestepping the whole child-window issue; I just drew and painted directly into the main window's client area, and everything works fine.

I think the original problem I had (the toolbar getting messed up, which is why I went to using a child window) was due to me using GetDC() ... ReleaseDC() in the WM_PAINT handler, instead of BeginPaint() ... EndPaint().

I would still like to know the answers to those basic questions I asked earlier, like whether one should only paint in response to a WM_PAINT message, or whether it's OK to paint at other times. And not as a matter of good style or whatever, but what is functionally the correct way to do it using WinAPI.

dedndave

well - i have read a few times that you should only paint during WM_PAINT
and then, only between BeginPaint and EndPaint
not sure i understand that one   :P

but, if you want to put something in the window.....
design the paint routine to handle it - perhaps some control flags to tell it something special needs to be painted
then, use InvalidateRect or InvalidateRgn to tell the OS that there is an "update region"
at that point, the OS will issue a WM_PAINT message, but at a low priority
i.e., only if no other messages are in the queue to be processed
to force an update, use UpdateWindow

when the WM_PAINT message is received, the PAINTSTRUCT has a rectangle of the area that requires updating
it also has the hDC (which is also in EAX after a BeginPaint call)
one other item in the PAINTSTRUCT is a flag to tell you if the background needs to be erased

i have done what you tried to do, before
not sure what your reason for doing it was,
but i was using the child window to eliminate flicker behind the scroll bars

in my case, the client area background color was user-selectable
if they chose some colors, the scrollbars flickered badly when they moved them or when they sized the window
by setting the client area background to COLOR_SCROLLBAR
and assigning the rest of the client area to a child window, it eliminated the flicker
i also used WS_CLIPCHILDREN - suggested by one of the forum members
i have learned to use that flag as a matter of habit for almost all windows i create   :P

MichaelW

Any drawing that you do on the client area of the window in your WM_PAINT handler will be done each time the window is redrawn.  Any drawing that you do elsewhere will not be redone each time the window is redrawn, so it will persist only until the next redraw.

;==============================================================================
    include \masm32\include\masm32rt.inc
;==============================================================================
    .data
        hInstance dd 0

        ps        PAINTSTRUCT <>
    .code
;==============================================================================

DlgProc proc hwndDlg:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

    SWITCH uMsg


        CASE WM_CTLCOLORDLG

            invoke GetStockObject, WHITE_BRUSH
            ret

        CASE WM_KEYDOWN

            SWITCH wParam

                CASE VK_D

                    invoke GetDC, hwndDlg
                    invoke TextOut, eax, 35, 20, chr$("XXX"), 3

                CASE VK_R

                    invoke InvalidateRect, hwndDlg, NULL, TRUE

            ENDSW

            .IF wParam == VK_SPACE

                invoke GetDC, hwndDlg
                invoke TextOut, eax, 35, 20, chr$("XXX"), 3

            .ENDIF

        CASE WM_PAINT

            invoke BeginPaint, hwndDlg, ADDR ps
            invoke TextOut, eax, 35, 45, chr$("YYY"), 3
            invoke EndPaint, hwndDlg, ADDR ps

        CASE WM_COMMAND

            SWITCH wParam

                CASE IDCANCEL

                    invoke EndDialog, hwndDlg, 0

            ENDSW

        CASE WM_CLOSE

            invoke EndDialog, hwndDlg, 0

    ENDSW

    xor   eax, eax
    ret

DlgProc endp

;==============================================================================
start:
;==============================================================================

    invoke GetModuleHandle, NULL
    mov   hInstance, eax

    Dialog "Test", \
           "MS Sans Serif",10, \
           WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
           0,0,0,50,50,1024

    CallModalDialog hInstance,0,DlgProc,NULL

    exit
;==============================================================================
end start


eschew obfuscation

NoCforMe

So the moral of the story is one should do all drawing within the WM_PAINT handler, unless of course you just want to draw something temporary, right?

dedndave

well - temporary is a bad term - lol
you want to stay in WM_PAINT - with few exceptions that i can think of
the reason is....
if the window is momentarily obscured by another window, moved offscreen, or minimized - then restored,
the only way for the required region to be updated is via WM_PAINT

an example of where you might not do it....
you have a child window with a caption bar
you set the caption text
in cases like these, the OS will update the appearance of the caption bar if it is required

essentially, your WM_PAINT handler should be capable of updating whatever is in the client area

jj2007

Quote from: dedndave on November 14, 2011, 10:40:16 PM
you have a child window with a caption bar
you set the caption text

You would use WM_NCPAINT in the child's subclass. Anyway, the PAINT handler doesn't have to do the painting: You can also just set a flag or a timer and do the painting elsewhere or later using GetDC.

NoCforMe

Instead of just giving you little tidbits of my code, I decided to strip out all the complex stuff and just post the bare bones of the program. Here it is. It creates a main window and a child window that occupies the client area of the main window (except for the space taken up by the toolbar). It still exhibits the same problem: the contents of the child window don't appear until after it's resized.

In fact, I added some code that makes me more convinced than ever that the problem is that the main window is somehow covering the child window (or that the child window isn't being properly created or displayed until after being resized). I first write some text to the main window; if the child were being properly displayed, you wouldn't see it (since the main window is below the child in the Z-order), but you can. Only after resizing does this text disappear and the text written to the child window appears.

If someone has the patience to look at this, I'd be most grateful. It requires a .rc file (provided) which loads the bitmap for the toolbar into the app.

ToutEnMasm


After read of your code:
You need to rewrite all your windows messages
Use the WM_CREATE to create the toolbar and the child windows
use the WM_PAINT message.
Put all your messages at the right place,in each window loop.
If you have no idea how to do this,use prostart (masm32),or one of the sample :
\masm32\examples\exampl01\generic\generic.asm


jj2007

Your child window is not yet sized when it gets the first WM_PAINT message - because there is not yet a child win handle when the WM_SIZE message is initially being handled. Here is a demo (there are more elegant ways to achieve this, though).

ChildWindowProc PROC hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
LOCAL hDC:HDC, ps:PAINTSTRUCT, gpRect:RECT

MOV EAX, uMsg
CMP EAX, WM_PAINT
JE do_paint

dodefault:
INVOKE DefWindowProc, hWin, uMsg, wParam, lParam
RET

do_paint:
; Hold off painting until we're ready:
INVOKE GetClientRect, MainWinHandle, ADDR gpRect
MOV EAX, gpRect.bottom
SUB EAX, 90
sub gpRect.right, 100
INVOKE MoveWindow, ChildWinHandle, 25, 90, gpRect.right, EAX, TRUE

INVOKE BeginPaint, hWin, ADDR ps

NoCforMe

Quote from: jj2007 on November 17, 2011, 07:30:55 AM
Your child window is not yet sized when it gets the first WM_PAINT message. Here is a demo (there are more elegant ways to achieve this, though).

I don't get it: the window's size is given when I create it:



; Get size of main & toolbar windows:
INVOKE GetClientRect, ToolbarHandle, ADDR gpRect
INVOKE GetClientRect, MainWinHandle, ADDR gpRect2
MOV EDX, gpRect2.bottom
SUB EDX, gpRect.bottom
; Use size to create child window:
INVOKE CreateWindowEx, 0, ADDR ChildClassName, NULL,
$childWinAttrs, 0, gpRect2.bottom, gpRect2.right, EDX,
MainWinHandle, NULL, hInst, NULL
MOV ChildWinHandle, EAX



Are you telling me that I can't use the window for drawing/painting until it gets re-sized? Why is that? After all, I created it with the WS_VISIBLE style.

Besides, you left out the part where I don't paint in the child window until well after it gets created (this is also for other reasons in my program: I have to prepare fonts and set up a lot of other stuff before painting):



do_paint:
; Hold off painting until we're ready:
CMP OK2paintFlag, TRUE
JNE dodefault
INVOKE BeginPaint, hWin, ADDR ps

...



jj2007

To be more precise: It is not yet properly sized...

   INVOKE   CreateWindowEx, 0, ADDR ChildClassName, NULL,
      $childWinAttrs, 0, gpRect2.bottom, gpRect2.right, EDX,
      MainWinHandle, NULL, hInst, NULL
   endif

Delete the 2

ToutEnMasm

Quote
Are you telling me that I can't use the window for drawing/painting until it gets re-sized? Why is that? After all, I created it with the WS_VISIBLE style.
You can ask many questions like that.Do a correct window loop as explain in
\masm32\examples\exampl01\generic\generic.asm      ;there is comment in it
You cannot write the loop messages as you want,follow the rules explains in the sample.


NoCforMe

Sorry, Yves, you're wrong.

jj, that was the problem all along! Another stoopid mistake on my part; I was creating the child window with nonsensical x- and y-values. Your suggestion fixed it.

Yves, you don't have to do everything according to the standard canonical examples. You do have to follow certain rules about when and how to do things, though. I'm trying to learn those rules, not just copy other people's examples blindly.

There's no reason you have to create things in a WM_CREATE handler, just because everyone else does it that way.