Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Is this a form bug? What is happening here?

Status
Not open for further replies.

Olaf Doschke

Programmer
Oct 13, 2004
14,847
DE
I encountered problems positioning a form, and I think this is a bug. Can you confirm this? Does anybody know what's going on?

Code to reproduce at the end.

I start a form with a red container, that has the target position and size of a child form. To illustrate what happens I show the subform and made screenshots what happens in each step of setting this forms left, top, width and height. The childform is set to have no border and titlebar and green backcolor, so it looks like just another green container, but the green rectangle is a subform put inside the main form via Windows SetParent and the red rectangle is a container within the main form.

The initial situation is as expected: SetParent works and puts the child into the main form into the top left corner. The target red rectangle is put there to be fully seen right now:

bugstep0_iypusq.png


So far, so fine, now the first step is to change the left property of the green form:
bugstep1_i8p7ei.png

The left position is correct, [highlight #FCE94F]but why did the top position change?[/highlight]
Ok, that wouldn't matter, as the next step can mend that, setting top:
bugstep2_wollub.png

Yes, the .Top position now is correct, [highlight #FCE94F]but why did left change once more?[/highlight]

The next two steps are unspectacular, they give the green form the correct size:
bugstep3_ufzcva.png

bugstep4_ppfggq.png


And last not least the workaround also is more elegant than setting all these properties one by one:
Using the Form.Move method on the green form puts the form into the right place with the (still) right size. You can also skip all the single steps and just do this, it's not needing already correct size, as Move not only sets Top and Left position but also Width and Height.
bugstep5_bb0mur.png


What happened here?
Is this Windows 10 (build 1803)?
Is it VFP (I use VFP9 with latest hotfix 09.00.0000.7423)?
Can you reproduce this?

Code to Reproduce:
Code:
oTestform = CreateObject("formbug")
oTestform.Show(1)

**************************************************
*-- Form:         form1 (...\vfp\tests\forms\formbug.scx)
*-- ParentClass:  form
*-- BaseClass:    form
*-- Time Stamp:   07/13/18 11:43:12 PM
*
DEFINE CLASS formbug AS form

	Top = 16
	Left = 18
	Height = 554
	Width = 530
	DoCreate = .T.
	Caption = "Form1"
	lactivated = .F.
	Name = "Form1"


	ADD OBJECT container1 AS container WITH ;
		Top = 264, ;
		Left = 96, ;
		Width = 288, ;
		Height = 144, ;
		BorderWidth = 0, ;
		BackColor = RGB(255,0,0), ;
		BorderColor = RGB(0,0,0), ;
		Name = "Container1"


	PROCEDURE Activate
		If NOT This.lActivated
		   This.lActivated = .T.

		   DECLARE SetParent IN WIN32API integer hWndChild, integer hWndParent
		   
		   Local loSubform
		   loSubform = CreateObject("form")
		   loSubForm.BorderStyle = 0
		   loSubForm.TitleBar    = 0
		   loSubForm.BackColor   = Rgb(0,255,0)
		   
		   SetParent(loSubForm.Hwnd, This.HWnd)

		   * To illustrate what happens show the form BEFORE adjusting position and size
		   loSubForm.Show()      
		   This.AddProperty("oSubform",loSubform)
		Endif
	ENDPROC


	PROCEDURE Click
   
      Set Step On 
		* doesn't work
		This.oSubform.Left   = This.container1.Left
		This.oSubform.Top    = This.container1.Top
		This.oSubform.Width  = This.container1.Width
		This.oSubform.Height = This.container1.Height

		* works
		This.oSubform.Move(      ;
		   This.container1.left ,;
		   This.container1.top  ,;
		   This.container1.width,;
		   This.container1.height)
	ENDPROC


ENDDEFINE
*
*-- EndDefine: formbug
**************************************************

As the code shows the child form is simply created by createobject("form") and also the main form is just a native base form, nothing special, no anchoring, nothing in that direction.
Thankfully Form.Move() is solving the issue, but if you inspect values of the subform properties you get strange values, too, different from the values just set. The container1 properties are fine all the way, but subform.left and top aren't just visually wrong, their values are even something else than what was set and what is effectively shown!

This is one of the weirdest bugs I've seen.

While Move works, it's a cumbersome workaround, if you only want to change one Property, like Left or Top position only.
Also notice the Top and Left position of the oSubform are also differing from what you see. For example, when the top positions are visually perfectly aligned, I get top=254 from the red container1 and top=481 from the green oSubform! And the form position isn't related to desktop or _screen (0,0), if you move the form around the subform follows as child form; its left and top values don't change and remain wrong. So you can't set these properties right and you can't read these properties right. Even after a Form.Move(), which means Left/Top are broken properties of forms. Why? How?

Bye, Oöaf.

Olaf Doschke Software Engineering
 
Olaf

Just to confirm the same results in VFP9 + (W10 | W7 | XP), and in VFP8 + XP.

 
Hi Olaf,
Something odd indeed. In stepping through the CLICK event when This.oSubform.Top = This.containter1.Top the value of Container1.Top is 264, but the assignment of that value to oSubform.Top is ignored, and This.osubform.Top at 471 remains the same. I've no explanation for why.

Actually looking closer at it, all those assignments fail. My only thought is, it's a child inside a parent, and it's not allowing the resize to take place?
Stumped.

Best Regards,
Scott
MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Thanks,

so according to you, atlopes, it's even an older bug, not OS related.

My line of thought was, as VFP is a C++ application the VFP form class has to be a subclass of the C++ TForm class and that inherits from the Windows System Form class
Winform of Windows itself and the HWND alone shows this relationship. In C++ itself you have about the same situation of direct properties Left and Top and Height and Width, so setting them should work 1:1, on the other side the Windows API is a bit more complicated with functions like SetWindowPos requiring a struct to set form position and you also have message in the Windows messaging system, that can influence form, like WM_MOVE: I thought Windows10 may have had an incompatible change in some of its API, that now hits VFP. But on the other side, this would affect so many things more than just VFP.

This has to be an older and already known VFP form bug. I don't find anything about that.

By the way, I used the SetParent of a form as child form to make use of a form as a container with scrollbars, which the VFP container class lacks. And I don't want to limit myself on having that for Top Level forms with "In Top-Level" child forms. I am not the first having this idea, as I remember Christof Wollenhaupt used that idea himself, too. I guess there even is a FoxTalk article about that.

@Scott: When you SetParent and thus create a child form hierarchy for the Windows OS even of "In Screen" forms that are already child forms of _screen and all sibling forms, the coordinate system of child forms becomes relative to its parent, even the WM_MOVE message mentions that the coordinates you send with the lparam parameter of a windows message are "parent-client coordinates for child windows" then.

OK, then I'll file this as bug to live with using Move to move a form to some wanted coordinates. What's missing now is a way to determine the real child form position. I'll investigate on that and post back.

Bye, Olaf.


Olaf Doschke Software Engineering
 
OK, I got it now.

Even though the Windows OS knows oSubform now is not a child of _screen anymore, VFP reports the coordinates relative to _screen. That still doesn't explain why only setting top also changes Left, but at least you can find out the real client position within the parent host form via WindowsAPI ScreenToClient:

Code:
Declare Integer GetWindowRect In user32;
         INTEGER hWindow,;
         STRING @lpRect

Declare Integer ScreenToClient In user32;
         INTEGER hWindow,;
         STRING @lpPoint

lcRect = Space(16)
GetWindowRect(This.oSubform.Hwnd, @lcRect)
ScreenToClient(This.Hwnd, @lcRect) 
lnLeft = CToBin(Left(lcRect,4),"4RS")
lnTop = CToBin(Right(lcRect,4),"4RS")

It seems like whatever value you set Thisform.oSubform.Left to Thisform.Left is added and likewise for Top, but even when you subtract Thisform Left and Top you don't position the subform correctly, alone the change of the left position when only changing the top property is surely a bug beyond the client coordinate system.

So you better make use of Move and to get currrent position get help from the Windows API.

What also works is setting the loSubform.Left, Top, Width and Height to Container1 values 1:1 before using SetParent(). But that only helps with initial positioning, not when you'd like to let this "container" react to host form resizing with anchored positioning.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Hi Olaf:

The problem is caused with those Win32 API functions altering internal VFP data.
If you want to open a form inside another form, you should do it with the VFP way.

This is the part of your example code changed for the VFP style of doing it, and does not couse this problem when changing individually left/top/width/height (and --as a plus-- is simpler than the API:)


[pre]
PROCEDURE Activate
If NOT This.lActivated
This.lActivated = .T.

Local loSubform
loSubform = CreateObject("form")
loSubForm.BorderStyle = 0
loSubForm.TitleBar = 0
loSubForm.BackColor = Rgb(0,255,0)

* To illustrate what happens show the form BEFORE adjusting position and size
This.AddProperty("oSubform",loSubform)
[highlight #FCE94F] ACTIVATE WINDOW (loSubForm.NAME) IN (THISFORM.Name)[/highlight]
Endif
ENDPROC
[/pre]

I tested this on VFP 09.00.0000.5815 on Windows 7 Enterprise
Please, confirm if this solves the problem on your setup.

Fernando D. Bozzo
 
Thanks, so it seems SetParent is doing less than ACTIVATE WINDOW ... IN ... and cuts VFP off of how it should treat Left and Top. As I already said it helps to set Top and Left before SetParent, too.
But yes, the ACTIVATE WINDOW done instead of SetParent works in my case: VFP version 09.00.0000.7423 in Win10 build 1803.

Thanks for pointing that out. I guess you could find out differences with process monitor, seems VFP binds itself to some windows events, when you do ACTIVATE WINDOW and doesn't do so when you use SetParent.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top