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));