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

NoCforMe

Got a problem with a program that uses a child window for painting and drawing. Unfortunately, code is a little too complicated to include here. I'll try to describe it clearly.

Basically I have a main window with a child window occupying its entire client area (except for a toolbar; the child window is sized to start below the toolbar).

I created the child window after registering a class for it:



$childWinAttrs EQU WS_CHILD OR WS_CLIPSIBLINGS OR WS_VISIBLE

INVOKE CreateWindowEx, WS_EX_OVERLAPPEDWINDOW, ADDR ChildClassName, NULL,
$childWinAttrs, 0, gpRect2.bottom, gpRect2.right, EDX,
MainWinHandle, NULL, hInst, NULL
MOV ChildWinHandle, EAX



After everything's set up, I do some drawing of text and simple graphics into the window. (It's a test bed for a larger project.) The problem is that nothing appears in the window until after I resize it--it's just blank. Here's the resizing code (in the parent's window procedure):



do_size:
INVOKE GetClientRect, ToolbarHandle, ADDR gpRect
MOV EAX, gpRect.bottom
MOV toolbarHeight, EAX
MOVZX EDX, WORD PTR lParam ;New window width.
; Resize toolbar:
INVOKE MoveWindow, ToolbarHandle, 0,  0, EDX, toolbarHeight, TRUE

; Resize child window:
INVOKE GetClientRect, MainWinHandle, ADDR gpRect
MOV EAX, gpRect.bottom
SUB EAX, toolbarHeight
INVOKE MoveWindow, ChildWinHandle, 0, toolbarHeight, gpRect.right, EAX, TRUE
; Bring to top of Z-order:
INVOKE SetWindowPos, ChildWinHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE OR SWP_NOSIZE \
OR SWP_SHOWWINDOW
XOR EAX, EAX
RET



Here's what I figure is happening: for some reason, until the windows are resized, the child window is behind the parent window, or otherwise rendered invisible. I tried doing this to bring the child to the top of the Z-order:



INVOKE SetWindowPos, ChildWinHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE OR SWP_NOSIZE \
OR SWP_SHOWWINDOW



but no joy. I can't figure out what's going on here. Are there some special tricks to get a child window like this to behave as expected? I also though of making the parent window transparent somehow, but I can't find anything on MSDN about that.

I hadn't planned on using a child window: originally I was just drawing into the main window's client area, which worked fine until I added a toolbar, at which point the toolbar stopped working correctly. I'm not sure, but somehow drawing into the client area DC seemed to upset the toolbar operation. The toolbar also uses tooltips, if that makes any difference. So that's why I ended up with a child window. Now if I could only get it to appear right away, I'd be happy.

NoCforMe

Interesting discovery: the first thing I do in the program is call InitCommonControlsEx(). I tried commenting it out. The result was no display of anything, no toolbar, and nothing in the child window either.

I can't help thinking that this has something to do with the fact that I have a toolbar with tooltips.

ToutEnMasm

You don't show how your code write in the window.
If you use the TextOut function,this one could only be used in a WM_PAINT message.
You don't show also the styles and extended styles of your windows.
This two things are fundamentals to know if the window work well or not.

NoCforMe

Yes, you're right of course.

Here are the main window styles:



(class styles)
MOV wc.style,  CS_HREDRAW or CS_VREDRAW or CS_BYTEALIGNWINDOW

$mainWinAttrs EQU WS_OVERLAPPEDWINDOW OR WS_CLIPCHILDREN OR WS_VISIBLE

INVOKE CreateWindowEx, WS_EX_OVERLAPPEDWINDOW, ADDR MainClassName, ADDR MainTitleText,
$mainWinAttrs, wX, wY, $mainWindowWidth, $mainWindowHeight,
NULL, NULL, hInst, NULL



Here's what I'm using to draw/paint in the child window:



INVOKE MoveToEx, hDC, currX, currY, NULL
MOV EDX, currX
ADD EDX, StaffWidth
INVOKE LineTo, hDC, EDX, currY



and for text:



; Set up font, text-align flags & background mode:
INVOKE SelectObject, hDC, [ESI + $Symbol.fHandle]
MOV oldFont, EAX
MOV EAX, [ESI + $Symbol.TAflags]
OR EAX, TA_NOUPDATECP
INVOKE SetTextAlign, hDC, EAX
MOV oldTA, EAX
INVOKE SetBkMode, hDC, TRANSPARENT
MOV oldBkMode, EAX

INVOKE TextOut, hDC, ECX, EDX, ADDR charBuffer, 1

; Reset stuff the way we found it:
INVOKE SelectObject, hDC, oldFont
INVOKE SetTextAlign, hDC, oldTA
INVOKE SetBkMode, hDC, oldBkMode



That's pretty much it.

jj2007

You need a DC for painting. one way to get it is to use InvalidRect for your child window, and to wait for a WM_PAINT message.

NoCforMe

Quote from: jj2007 on November 13, 2011, 07:26:13 AM
You need a DC for painting. one way to get it is to use InvalidRect for your child window, and to wait for a WM_PAINT message.

But I do have a DC for painting:



INVOKE GetDC, ChildWinHandle
MOV hDC, EAX



Don't I always have a DC I can use for painting? Or do I have to wait for certain conditions before starting painting?

My theory is still that I'm actually able to paint and draw, I just can't see it because the edit window is behind the parent window. Could be wrong, though.

I tried replacing GetDC() ... ReleaseDC() with BeginPaint() ... EndPaint(), but still no luck.

So let me see if I've got this straight: I can only use Begin ... EndPaint in response to a WM_PAINT message, right?

So what if I want to paint/draw into a window but not in the window proc? When/under what circumstances can I do this?

Besides the WM_PAINT issue, what's the difference between getting a DC with GetDC() and using Begin ... EndPaint()?

ToutEnMasm


Quote
.data
   lgfnt           LOGFONT <14,0,0,0,0,0,0,0,0,0,0,0,0,"Lucida Console">
   hFont dd 0
.code
   .elseif uMsg == WM_PAINT
      invoke BeginPaint,hwnd,ADDR paintstruct
      mov hdc,eax
      invoke CreateFontIndirect,ADDR lgfnt
      mov hFont,eax
      invoke SelectObject,hdc,hFont
      invoke lstrlen,ADDR chaine
      invoke TextOut,hdc,20,20,ADDR chaine,eax
      ;invoke DeleteObject,hFont   

NoCforMe

The only difference between that example you posted and what I'm doing is that I'm preparing my fonts beforehand and storing their handles in some structures to make them accessible. Other than that, I don't see any difference. So what do you think my problem is here?

I'm almost positive that the problem is the child window being obscured by the parent. I just changed my window-creation and resizing code so the child window is smaller than the parent's client area, and added a border (WS_BORDER) so I'd be sure to see it. I can't see the child when it's created, but I can see it after resizing. ?????

I don't think this has anything to do with painting and drawing.

dedndave

the parent window will not obscure the child - that is not the nature of the child/parent relationship

during WM_CREATE, a WM_SIZE message is sent to the parent window
what this means is, be prepared to handle WM_SIZE early
in the WM_SIZE handler, if you reference a handle that is stored in a global variable and has not yet been initialized, strange things may happen
this goes back to that other discussion about what things should be done in WM_CREATE
i generally try to create child windows during WM_CREATE so their handle values are initialized early

this may not be the issue with your code
without a more complete example, it is hard to say
however, you may not want to post your code at this time
that's ok - look at the many examples that create child windows and see how they differ from your code   :U

jj2007

Another attempt to help you without seeing your code. For me this works in a very similar case.

  SWITCH uMsg
  CASE WM_CREATE
....
invoke SetTimer, hWnd, 123, 500, 0

  CASE WM_TIMER
invoke KillTimer, hWnd, 123
if 1   ; test 0 or 1, see if things change
invoke InvalidateRect, hChild, 0, 0
endif

drizz

Do you handle WM_ERASEBKGND message?

QuoteIf hbrBackground is NULL, the application should process the WM_ERASEBKGND message and erase the background.
The truth cannot be learned ... it can only be recognized.

NoCforMe

But my background brush isn't NULL (I assume you're talking about what gets passed to RegisterClassEx() ). I don't think that's the issue.

Dave, what you said is worth considering. It might have everything to do with the order in which I'm doing things.

I moved all my creation stuff (toolbar window, tooltips & child window creation) to the WM_CREATE handler. Now I get nothing--no toolbar, no nothing.

So here's the deal: I'm in kind of a bind since certain things depend on certain other things. For instance, I'm sizing the child window based on the size of the parent window AND the size of the toolbar, since I want the child to fill the entire client area. So I can't resize the whole thing until everything's created.

I'm not sure that WM_CREATE is the best place to do this.

Here's what needs done:


o Create parent window
o Create toolbar (& tooltip stuff)
o Create child window


If I put things into my window procedure, I'd have


o Create parent window--> WM_CREATE
o WM_CREATE handler: create toolbar, tooltips & child window


Another way to handle this sequencing situation is just to set a "safe to paint" flag to be used by the WM_PAINT handler:


(WinMain() )
o create main window
o create toolbar & tooltips
o create child window
o load fonts, etc.
o set up other stuff needed for drawing & painting
o set "safe to paint" flag

case WM_PAINT:
if (safe to paint)
   paint away ...


I had done this earlier, and it worked OK, except for the problem of this topic, the child window not appearing until resized.

One question about putting stuff in the WM_CREATE handler: if I create other stuff in that handler, what happens to the WM_CREATE messages that they generate? Don't I have a recursive situation here? At least in the case of the toolbar, which share the window procedure with the main window (the child window has its own window proc).

Regarding WM_PAINT messages: what happens if I ignore them? Do they stack up? or does the system keep sending one message over and over until it's processed? or does the default window handler take care of it?

I need a much better understanding of all this sequencing stuff than I'm able to get from either MSDN or, so far, from folks here ...

dedndave

ok - i will come up with a little program
to start off, i will use Hutch's ProStart...
http://www.masm32.com/board/index.php?topic=12462.0

i think that's the latest version - it's a warmed-up version of CodeGen
a fun little program you might enjoy
i learned a lot from it when i first started writing windows programs

MichaelW

Quote
I need a much better understanding of all this sequencing stuff than I'm able to get from either MSDN or, so far, from folks here ...

With so little of your code visible to us there are too many possibilities as to what is wrong with it.

eschew obfuscation

dedndave

ok - here we go
i started with Hutch's ProStart code
i moved the toolbar include stuff into Project.asm and Project.inc
i also made a couple changes to the make batch file
then, i added the child window
all my additions are in the asm file, rather than putting some things in the inc file
i did it that way so you could find it easily
everything i added to create the child is surrounded like this
;#############################
; Added
;#############################

;stuff i added

;#############################


notice that, when i create the child window, the position and size parameters are all set to 0
we let the WM_SIZE code take care of it   :U

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