if (in Delphi) I do
Panel1.ManualFloat(Rect(500,500,600,600));
the panel is floated not at the specified Rect location, but instead in a sort of windows default location. How do I get a panel (or other control) to float at a specified location. It does seem to have the correct shape however. Is there some other property I need to set to make it work correctly?
Edit: Just to make things clear. I would expect the above code to make the panel a 100x100 square located at (500x500) relative to the top left hand corner of the screen, which it doesn't. The shape is correct but location is not. If subsequent controls are floated they are cascaded down the screen.
Edit2: This doesn't seem to be a problem in Delphi 7, but is in Delphi 2007 through XE2 (and possibly earlier)
Don't look further: Its a bug in the VCL.
ManualFloat
creates a floating window and sets its Top
, Left
values in TControl.CreateFloatingDockSite(Bounds: TRect)
and later sets its ClientWidth
.
That is a mistake because doing that forces the WindowHandle creation (it didn't have a Handle yet) in
function TCustomForm.GetClientRect: TRect;
begin
if IsIconic(Handle) then // <===
And that calls the default positioning of the Window (cascading yadda yadda...) resetting the Top
and Left
The fix would be to set the ClientWidth
and ClientHeight
before setting the Top
and Left
properties in TControl.CreateFloatingDockSite(Bounds: TRect)
Update: the fixed code in Controls.pas
function TControl.CreateFloatingDockSite(Bounds: TRect): TWinControl;
begin
Result := nil;
if (FloatingDockSiteClass <> nil) and
(FloatingDockSiteClass <> TWinControlClass(ClassType)) then
begin
Result := FloatingDockSiteClass.Create(Application);
with Bounds do
begin
// Setting Client area can create the window handle and reset Top and Left
Result.ClientWidth := Right - Left;
Result.ClientHeight := Bottom - Top;
// It is now safe to position the window where asked
Result.Top := Top;
Result.Left := Left;
end;
end;
end;
Forms.TCustomDockForm
has BorderStyle = bsSizeToolWin
and isn't iconic. That's why I asked if OP has an own FloatingDockSiteClass
assigned for the panel - NGLN 2012-04-04 19:52
ClientRect
doesn't recreate a window. And no I don't see: I have tried all the examples from my answer as well as OP's code and they work as by the VCL intented (in D7 though) - NGLN 2012-04-04 22:23
Like the TRect
parameter's name of the function - ScreenPos
- kind of says it already, the coordinates are in screen units rather then that of the parent.
If you want the panel to stay at the same place where it was, translate the coordinates relative to the screen:
with Panel1.ClientToScreen(Point(0, 0)) do
Panel1.ManualFloat(Bounds(X, Y, 100, 100));
Or, to include the panel's border:
if Panel1.HasParent then
with Panel1.Parent.ClientToScreen(Panel1.BoundsRect.TopLeft) do
Panel1.ManualFloat(Bounds(X, Y, 100, 100));
Or, to translate to a specific coordinate relative to the parent, use:
if Panel1.HasParent then
with Panel1.Parent.ClientOrigin do
Panel1.ManualFloat(Bounds(X + 500, Y + 500, 100, 100));
FloatingDockSiteClass
? Otherwise I could not explain why this not functions - NGLN 2012-04-04 03:46
ManualFloat
,Rect(500, 500, 600, 600)
is 500 pixels down and left from the top of the screen, always. (It's basically the "windows default location" type area, becauseManualFloat
uses screen coordinates and not window coordinates.) Are you expecting it to be in client coordinates instead (based on your form's location) - Ken White 2012-04-04 02:24