ManualFloat не используя указанную прямую кишку

если (в Delphi) я делаю

Panel1.ManualFloat(Rect(500,500,600,600));

панель перемещается не в указанное расположение Rect, а в своего рода расположение windows по умолчанию. Как получить панель (или другой элемент управления), чтобы плавать в указанном месте. Однако, похоже, у него правильная форма. Есть ли какое-то другое свойство, которое мне нужно установить, чтобы оно работало правильно?

Edit: просто чтобы прояснить ситуацию. Я ожидал бы, что приведенный выше код сделает панель площадью 100x100 расположен в (500x500) относительно верхнего левого угла экрана, чего нет. Форма правильная, а расположение-нет. Если последующие элементы управления плавают, они каскадируются вниз по экрану.

Edit2: это, похоже, не проблема в Delphi 7, но в Delphi 2007 через XE2 (и, возможно, ранее)

2 ответов


не смотрите дальше: это ошибка в VCL.

ManualFloat создает плавающее окно и устанавливает его Top, Left значения TControl.CreateFloatingDockSite(Bounds: TRect) и потом устанавливает его ClientWidth.

это ошибка, потому что это заставляет создание WindowHandle (у него еще не было дескриптора) в

function TCustomForm.GetClientRect: TRect;
begin
  if IsIconic(Handle) then // <===

и это вызывает позиционирование окна по умолчанию (каскадное yadda yadda...) сброс Top и Left

исправление будет установить the ClientWidth и ClientHeight перед установкой Top и Left свойства TControl.CreateFloatingDockSite(Bounds: TRect)

Update: фиксированный код в элементах управления.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;

как о функции - ScreenPos - вид говорит это уже, координаты находятся в единицах экрана, а не в Родительском.

если вы хотите, чтобы панель оставалась на том же месте, где она была, переведите координаты относительно экрана:

  with Panel1.ClientToScreen(Point(0, 0)) do
    Panel1.ManualFloat(Bounds(X, Y, 100, 100));

или, чтобы включить границу панели:

  if Panel1.HasParent then
    with Panel1.Parent.ClientToScreen(Panel1.BoundsRect.TopLeft) do
      Panel1.ManualFloat(Bounds(X, Y, 100, 100));

или, чтобы перевести на определенную координату относительно родителя, используйте:

  if Panel1.HasParent then
    with Panel1.Parent.ClientOrigin do
      Panel1.ManualFloat(Bounds(X + 500, Y + 500, 100, 100));