From: Stephen P. <Ste...@uc...> - 2003-12-16 11:14:59
|
Hi, The problem is simply that the implementation of relative co-ordinates = is not done properly.=20 If you make a parent window and give it a child window that is a = DialogBox, then position the main window at screen co-ordinates 100x100, = then call $CHILD->Top(0); to position child window at the very top of the screen, the child window = will move to the top of the screen but WILL ALSO MOVE 100px TO THE LEFT = because Win32::GUI is treating the relative X co-ordinate it gets using = ScreenToClient() as an absolute co-ordinate when it passes it to = SetWindowPos(). The Y co-ordinate given as the argument (0) is not = converted by ScreenToClient() since it's not part of (and not put into) = the myRect struct, and therefore is passed directly to SetWindowPos = resulting in correct, absolute positioning for the Y co-ordinate. The = same goes for the Left() function, but the co-ordinate affected by the = bug is then the Y co-ordinate instead of the X co-ordinate. This is the bug I'm on about, and this is the bug that I believe I have = fixed. The child window must be a DialogBox. The correct behaviour perhaps, for dialogboxes, is for Top(0) to = position them at the Y co-ordinate of their parent, however this is not = what I would expect Top(0) to do. To be honest I'm not sure why = Win32::GUI makes the distinction between a Window and a DialogBox = anyway, internally both are the same thing with slightly different = styles. I can't see any real justification for just using = Win32::GUI::Window at all (other than the fact that it does not suffer = from this bug :) ). The code here demonstrates the problem: use Win32::GUI; my $PARENT =3D new Win32::GUI::DialogBox( -name =3D> "ParentWin", -left =3D> 100, -top =3D> 100, -width =3D> 100, -height =3D> 100, -text =3D> "Parent" ); $PARENT->Show; my $CHILD =3D new Win32::GUI::DialogBox( -name =3D> "ChildWin", -left =3D> 400, -top =3D> 200, -width =3D> 100, -height =3D> 100, -text =3D> "Child", -parent =3D> $PARENT ); $PARENT->AddButton( -name =3D> "movechild", -left =3D> 10, -top =3D> 10, -right =3D> 10, -width =3D> 70, -height =3D> 25, -text =3D> "Move child" ); $CHILD->Show; Win32::GUI::Dialog; sub ::movechild_Click { print "Child X co-ordinate: ".$CHILD->Left()."\n"; $CHILD->Top(0); print "Child X co-ordinate after Top(0): ".$CHILD->Left()."\n"; return 0; }; If that's the behaviour YOU expect then I strongly disagree with you. = Setting Top() should certainly NOT affect Left(). Steve -----Original Message----- From: per...@li... [mailto:per...@li...]On Behalf Of Laurent ROCHER Sent: 15 December 2003 23:03 To: Steve Pick Cc: Win32 GUI Hackers Subject: Re: [perl-win32-gui-hackers] bugfixed some cvs Hi, > Just fixed a bug with windows that had the -parent option given, and = were > then positioned with the Left() and Top() methods. These methods were > detecting that the window had a parent and were translating X (in the = case > of Top() ) and Y (in the case of Left() ) into the current X or Y > co-ordinate minus the parent X or Y co-ordinate, causing child windows that > were sent multiple Top(somenumber) or Left(somenumber) calls to "walk" > horizontally or vertically across the desktop in steps dependent on = the > position of their parent window. Nasty. I'm not understand your problem and bug fix. For me, coordinate of a child windows is relative to parent window and = not screen relative. Only main window are screen coordinate. I have test sample below with your change, and button move when sizing = or main window move. Button should alway be at 5,5 in main window, with AddButton or with new GUI::Button + parent option. use Win32::GUI; $W =3D new Win32::GUI::Window( -title =3D> "test", -left =3D> 100, -top =3D> 100, -width =3D> 280, -height =3D> 280, -name =3D> "Window", ); # $button =3D $W->AddButton( # This keep button = as 5,5 $button =3D new Win32::GUI::Button( -parent =3D> $W, # This move button -name =3D> "Simple1", -left =3D> 5, -top =3D> 5, -width =3D> 122, -height =3D> 400, -text =3D> "Just button", ); $W->Show; Win32::GUI::Dialog(); sub Window_Terminate { return -1; } sub Window_Resize { $button->Left(5); $button->Top(5); print "Resize !!!\n"; } > > You might be confused as to why I fixed this in quite the way I did (setting > a flag in userdata if the user specifies -parent). > > I did this because I wanted to preserve the ability to explicitly call > SetParent on a window to insert it into another window's client area. = This > is an especially handy trick for making hidable/moveable panes without > moving all the widgets one by one. If I simply detected if the thing = that > was having Top/Left set was a window or not, it would not translate = the > co-ordinates when it should do. If you want move or hide a group of widget, it's better to create all = widget directly to a parent/container window. And move or hide this container window. Some thing like that : use Win32::GUI; $W =3D new Win32::GUI::Window( -title =3D> "test", -pos =3D> [100, 100], -size =3D> [280, 280], -name =3D> "Window", ); $Grp1 =3D $W->AddGroupbox( -name =3D> "Groupe", -text =3D> "Groupe", -pos =3D> [5, 5], -size =3D> [122, 200], ); new Win32::GUI::Button ( -parent =3D> $Grp1, -name =3D> "Test", -text =3D> "Test!!!", -pos =3D> [20, 20] ); $W->AddButton ( -name =3D> "Hide", -text =3D> "Hide it", -pos =3D> [200, 5], ); $W->AddButton ( -name =3D> "Show", -text =3D> "Show it", -pos =3D> [ 200, 40], ); $W->AddButton ( -name =3D> "Move", -text =3D> "Move it", -pos =3D> [200, 75], ); $W->Show; Win32::GUI::Dialog(); sub Window_Terminate { return -1; } sub Test_Click { print "test !!!\n"; } sub Hide_Click { $Grp1->Hide(); } sub Show_Click { $Grp1->Show(); } sub Move_Click { $Grp1->Top($Grp1->Top + 2); } You can look on my TabFrame package, i have a Frame.pm class with act as window container. Frame heritate from Win32::GUI::Window so you can use standard = Add<Control> method. If you really need use SetParent for runtime change, i think it's = probably better to add set functionnality to AbsLeft and AbsTop. And use those functions rather Left and Top. Laurent. ------------------------------------------------------- This SF.net email is sponsored by: SF.net Giveback Program. Does SourceForge.net help you be more productive? Does it help you create better code? SHARE THE LOVE, and help us help YOU! Click Here: http://sourceforge.net/donate/ _______________________________________________ Perl-Win32-GUI-Hackers mailing list Per...@li... https://lists.sourceforge.net/lists/listinfo/perl-win32-gui-hackers |
From: Stephen P. <Ste...@uc...> - 2003-12-17 10:32:42
|
Hi Laurent, I like your IsChild() method much better than my kludge. You're welcome = to replace my changes in the CVS with your method of doing it. It seems = a much more elegant solution. Thanks for looking into this, Steve -----Original Message----- From: Laurent ROCHER [mailto:ro...@cl...] Sent: 16 December 2003 19:13 To: Stephen Pick Cc: Win32 GUI Hackers Subject: Re: [perl-win32-gui-hackers] bugfixed some cvs OK, i understand your problem now. I agree Main window and Dialog box have screen coordinate. Dialog box have a parent window but it's not a child window. No translation must be done. But, you change break use of -parent option for normal child window = (show in my sample). In this case, it's better to replace in Top and Left : parent =3D GetParent(handle); perlud =3D (LPPERLWIN32GUI_USERDATA) GetWindowLong(handle, = GWL_USERDATA); if(perlud && perlud->hasParentAttribute =3D=3D FALSE && parent) ScreenToClient(parent, &myPt); with : parent =3D GetParent(handle); if (parent && IsChild(parent, handle)) ScreenToClient(parent, = &myPt); IsChild() do job you want. It's return false when handle is a dialog = window. Are you agree ? Laurent. ----- Original Message -----=20 From: "Stephen Pick" Subject: RE: [perl-win32-gui-hackers] bugfixed some cvs Hi, The problem is simply that the implementation of relative co-ordinates = is not done properly. If you make a parent window and give it a child window that is a = DialogBox, then position the main window at screen co-ordinates 100x100, then call $CHILD->Top(0); to position child window at the very top of the screen, the child window will move to the top of the screen but WILL ALSO MOVE 100px TO THE LEFT because Win32::GUI is treating the relative X co-ordinate it gets using ScreenToClient() as an absolute co-ordinate when it passes it to SetWindowPos(). The Y co-ordinate given as the argument (0) is not = converted by ScreenToClient() since it's not part of (and not put into) the myRect struct, and therefore is passed directly to SetWindowPos resulting in correct, absolute positioning for the Y co-ordinate. The same goes for = the Left() function, but the co-ordinate affected by the bug is then the Y co-ordinate instead of the X co-ordinate. This is the bug I'm on about, and this is the bug that I believe I have fixed. The child window must be a DialogBox. The correct behaviour perhaps, for dialogboxes, is for Top(0) to = position them at the Y co-ordinate of their parent, however this is not what I = would expect Top(0) to do. To be honest I'm not sure why Win32::GUI makes the distinction between a Window and a DialogBox anyway, internally both are = the same thing with slightly different styles. I can't see any real justification for just using Win32::GUI::Window at all (other than the = fact that it does not suffer from this bug :) ). The code here demonstrates the problem: ... If that's the behaviour YOU expect then I strongly disagree with you. Setting Top() should certainly NOT affect Left(). Steve |
From: Laurent R. <ro...@cl...> - 2003-12-17 18:55:39
|
> I like your IsChild() method much better than my kludge. > You're welcome to replace my changes in the CVS with your method of doing it. It seems a much more elegant solution. OK, i commit IsChild solution on CVS. Laurent. |
From: Laurent R. <ro...@cl...> - 2003-12-16 19:12:52
|
OK, i understand your problem now. I agree Main window and Dialog box have screen coordinate. Dialog box have a parent window but it's not a child window. No translation must be done. But, you change break use of -parent option for normal child window (show in my sample). In this case, it's better to replace in Top and Left : parent = GetParent(handle); perlud = (LPPERLWIN32GUI_USERDATA) GetWindowLong(handle, GWL_USERDATA); if(perlud && perlud->hasParentAttribute == FALSE && parent) ScreenToClient(parent, &myPt); with : parent = GetParent(handle); if (parent && IsChild(parent, handle)) ScreenToClient(parent, &myPt); IsChild() do job you want. It's return false when handle is a dialog window. Are you agree ? Laurent. ----- Original Message ----- From: "Stephen Pick" Subject: RE: [perl-win32-gui-hackers] bugfixed some cvs Hi, The problem is simply that the implementation of relative co-ordinates is not done properly. If you make a parent window and give it a child window that is a DialogBox, then position the main window at screen co-ordinates 100x100, then call $CHILD->Top(0); to position child window at the very top of the screen, the child window will move to the top of the screen but WILL ALSO MOVE 100px TO THE LEFT because Win32::GUI is treating the relative X co-ordinate it gets using ScreenToClient() as an absolute co-ordinate when it passes it to SetWindowPos(). The Y co-ordinate given as the argument (0) is not converted by ScreenToClient() since it's not part of (and not put into) the myRect struct, and therefore is passed directly to SetWindowPos resulting in correct, absolute positioning for the Y co-ordinate. The same goes for the Left() function, but the co-ordinate affected by the bug is then the Y co-ordinate instead of the X co-ordinate. This is the bug I'm on about, and this is the bug that I believe I have fixed. The child window must be a DialogBox. The correct behaviour perhaps, for dialogboxes, is for Top(0) to position them at the Y co-ordinate of their parent, however this is not what I would expect Top(0) to do. To be honest I'm not sure why Win32::GUI makes the distinction between a Window and a DialogBox anyway, internally both are the same thing with slightly different styles. I can't see any real justification for just using Win32::GUI::Window at all (other than the fact that it does not suffer from this bug :) ). The code here demonstrates the problem: ... If that's the behaviour YOU expect then I strongly disagree with you. Setting Top() should certainly NOT affect Left(). Steve |