Search code examples
delphivcldelphi-xe6

How to move a panel or frame by dragging it or any component inside it?


In a white full screen form I will have seven frames from the same source. I want to move them with the mouse and save that position when exit, for loading later in that same position. I can move a panel if I hold mouse down on it and move it, from a code I got in delphi.about.com

But if I click in a WinControl inside that panel, of course I do not get the OnMouseDown from the panel.

How can I move the panel (or the frame) moving any control inside it without coding on every component it has?


Solution

  • Here is a quick example that explains what I am referring to by an overlay:

    TTransparentPanel = class(TPanel)
    protected
      procedure WMEraseBkGnd(var msg: TWMEraseBkGnd); message WM_ERASEBKGND;
      procedure CreateParams(var params: TCreateParams); override;
    end;
    
    procedure TTransparentPanel.CreateParams(var params: TCreateParams);
    begin
      inherited CreateParams(params);
      params.ExStyle := params.ExStyle or WS_EX_TRANSPARENT;
    end;
    
    procedure TTransparentPanel.WMEraseBkGnd(var msg: TWMEraseBkGnd);
    begin
      SetBkMode (msg.DC, TRANSPARENT);
      msg.result := 1;
    end;
    

    In the form you have something like this:

    procedure TFormTest.FormCreate(Sender: TObject);
    begin
      FTransparentPanel := TTransparentPanel.Create(Self);
      FTransparentPanel.Parent := self;
      FTransparentPanel.Align := alClient;
      FTransparentPanel.Visible := True;
      FTransparentPanel.OnMouseDown := FormMouseDown;
      FTransparentPanel.OnMouseUp := FormMouseUp;
      FTransparentPanel.OnMouseMove := FormMouseMove;
    end;
    
    procedure TFormTest.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift:
        TShiftState; X, Y: Integer);
    var
      I: Integer;
    begin
      // Check if there is a control under X, Y
      FMoveControl := nil;
      for I := 0 to ControlCount - 1 do
      begin
        if Controls[I] <> FTransparentPanel then
        begin
          if (Controls[I].Left <= X) and (Controls[I].Top <= Y) and
             ((Controls[I].Left + Controls[I].Width) >= X) and ((Controls[I].Top + Controls[I].Height) >= Y) then
          begin
            FMoveControl := Controls[I];
            break;
          end;
        end;
      end;
      if Assigned(FMoveControl) then
      begin
        FStartLeft := FMoveControl.Left;
        FStartTop := FMoveControl.Top;
        FStartX := X;
        FStartY := Y;
      end;
    end;
    
    procedure TFormTest.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y:
        Integer);
    begin
      // Move it
      if Assigned(FMoveControl) then
      begin
        FMoveControl.Left := FStartLeft + (X - FStartX);
        FMoveControl.Top := FStartTop + (Y - FStartY);
      end;
    end;
    
    procedure TFormTest.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift:
        TShiftState; X, Y: Integer);
    begin
      FMoveControl := nil;
    end;
    

    This flashes a little bit when you move the control but should give you an idea on how to proceed.