7

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)

Alister
  • 6,527
  • 4
  • 46
  • 70
  • When used with `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, because `ManualFloat` 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 Apr 04 '12 at 02:24
  • @KenWhite, thanks Ken but is not what happens. The panel is a 100x100 square as would be expected, but not at location (500,500) relative to the top left had corner of the screen – Alister Apr 04 '12 at 03:33
  • @KenWhite, try his code and see for yourself... – Francesca Apr 04 '12 at 20:22
  • No cascading nor problem here with D7. Do you use a custom dock manager or a custom dock site class? – NGLN Apr 04 '12 at 22:24
  • ... but problem with versions after D7 and certainly in XE2. – Francesca Apr 05 '12 at 00:26

2 Answers2

5

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;
Francesca
  • 21,452
  • 4
  • 49
  • 90
  • But the default floating dock site class `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 Apr 04 '12 at 19:52
  • @NGLN. BorderStyle or iconic is irrelevant. Setting the Top and Left before creating the Window Handle is a sure way to lose them... Just try like the OP with a simple example: a form, a panel, a button with his code to set the panel floating and see... – Francesca Apr 04 '12 at 20:21
  • Setting or getting `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 Apr 04 '12 at 22:23
  • +1, A six year old report of the bug (note 'poDesigned' in the workaround section in the report (so that 'CreateParams' should assign X, Y -> Left, Top)): http://qc.embarcadero.com/wc/qcmain.aspx?d=28614 – Sertac Akyuz Apr 04 '12 at 23:23
  • @NGLN, tested in XE and XE2, not in D7...(note from the bug unearthed by Sertac: *"in Delphi before version 7 inclusive on-default property Position was equal poDesigned (for all forms)"*). Also I did not say ClientRect **recreate** a window, but if the window does not **yet** have a Handle, it will create it and mess up the Top and Left. – Francesca Apr 05 '12 at 00:21
  • Thanks François, I think I'll pass on editing controls.pas however ;-) – Alister Apr 05 '12 at 01:19
1

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));
NGLN
  • 43,011
  • 8
  • 105
  • 200
  • Yes I'm aware of the required translation of screen coordinates. The problem is that ManualFloat ignores the X and Y (to use your variables from above). Works perfectly with Forms but I can't get it to work with a panel. The width and height are correct however. If I set X and Y to 0, I would expect the panel to appear in the top left hand corner of the screen, but it doesn't which is where I'm stuck. – Alister Apr 04 '12 at 03:31
  • Are you using a own `FloatingDockSiteClass`? Otherwise I could not explain why this not functions. – NGLN Apr 04 '12 at 03:46
  • @NGLN *"Otherwise I could not explain why this not functions."*, try his code and see.. – Francesca Apr 04 '12 at 20:24
  • @François All code from my posts is tested, as well as OP's code in this case: the dock window simply appears there where it should. – NGLN Apr 04 '12 at 22:23
  • @NGLN, not in any Delphi version after D7. – Francesca Apr 05 '12 at 00:24
  • That is a pretty hideous use of the with statement, it took me a bit to work out what you were doing. – Alister Apr 13 '12 at 04:27