3

I want to create a MDI application with it's own task bar so the user can have fast access to the child windows he/she wants to bring to front. Then I had the idea that an user who works with two or more monitors could drag on of the child windows from inside the main form of my application into outside of it, into another monitor for example.

How can it be done?

NaN
  • 8,596
  • 20
  • 79
  • 153
  • 1
    What you are describing is not an MDI application since I do not believe that MDI will readily support what you need. Rather it's an MDI application which uses dockable forms. The canonical Delphi example of such is the Delphi IDE itself. Read up on docking and it should be pretty routine. – David Heffernan May 14 '13 at 19:24
  • Delphi IDE does not have a container as a base for those dockable items. MDI has a main form with the whole window as a container in which the child is in. When you pull one of them out, it become like a main form itself. So what am I describing? Maybe a third stuff? – NaN May 14 '13 at 20:09
  • Well, you can simply build a main form and add your own container. – David Heffernan May 14 '13 at 20:23
  • 3
    Windows 7 adds support for taskbar access to MDI child windows, via the `ITaskbarList3` interface. But it is not possible to "pull off" an MDI child window into a floating window. Either create docking windows, or move your MDI content onto Frames that you can re-parent between MDI child Forms and floating Forms when needed. – Remy Lebeau May 14 '13 at 20:29
  • @DavidHeffernan did you tested NGLN answer? It's just that I meant and it worked perfectly! :-) – NaN May 16 '13 at 11:25
  • How can you tell that the user wants to drag out rather than adjust position? I'd do it with a context menu action if it's MDI. – David Heffernan May 16 '13 at 12:02
  • To drag out to put the child windows in a separated monitor, maximized or not, to work like a BOSS :-) – NaN May 17 '13 at 00:51
  • I don't understand that. How can you tell the user wanted to convert to standalone window and not just move the child window? Or do you not let them move child windows anymore? – David Heffernan May 17 '13 at 10:55
  • Consider that the user have two screen monitors: one in the left of the other. Then, what is the best: the user divide the the MDI main form between the two monitors and use 3 from 4 children in one monitor and the other 4th child in the second monitor? OR he/she uses the MDI form maximized in the first monitor with the 3 children inside and another ex-child outside in the other monitor? – NaN May 17 '13 at 19:11
  • Possible Answer: The user may have some text or some buttons divided in two when the MDI MAIN FORM is divided in two because of the two monitors, so I THINK, the second option is the best. I may take some screenshots if anyone did not understand, for that example. – NaN May 17 '13 at 19:12

1 Answers1

4

Maybe this example MDI client form code serves inspiration:

unit Unit3;

interface

uses
  Windows, Messages, Controls, Forms;

type
  TForm3 = class(TForm)
  private
    FSizing: Boolean;
    procedure WMNCMouseLeave(var Message: TMessage);
      message WM_NCMOUSELEAVE;
    procedure WMWindowPosChanged(var Message: TWMWindowPosChanged);
      message WM_WINDOWPOSCHANGED;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure Resize; override;
  end;

implementation

{$R *.dfm}

{ TForm3 }

var
  FDragging: Boolean = False;

procedure TForm3.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  if FormStyle = fsNormal then
    Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW
  else
    Params.ExStyle := Params.ExStyle and not WS_EX_APPWINDOW;
end;

procedure TForm3.Resize;
begin
  inherited Resize;
  FSizing := True;
end;

procedure TForm3.WMNCMouseLeave(var Message: TMessage);
begin
  inherited;
  FDragging := False;
end;

procedure TForm3.WMWindowPosChanged(var Message: TWMWindowPosChanged);
var
  P: TPoint;
  F: TCustomForm;
  R: TRect;
begin
  inherited;
  if not FDragging and not FSizing and not (fsShowing in FormState) and
    (WindowState = wsNormal) then
  begin
    F := Application.MainForm;
    P := F.ScreenToClient(Mouse.CursorPos);
    R := F.ClientRect;
    InflateRect(R, -5, -5);
    if not PtInRect(R, P) and (FormStyle = fsMDIChild) then
    begin
      FDragging := True;
      FormStyle := fsNormal;
      Top := Top + F.Top;
      Left := Left + F.Left;
    end
    else if PtInRect(R, P) and (FormStyle = fsNormal) then
    begin
      FDragging := True;
      FormStyle := fsMDIChild;
    end;
  end;
  FSizing := False;
end;

end.
NGLN
  • 43,011
  • 8
  • 105
  • 200
  • This is very fun, it does the job! But I am going to work a little bit on that, because when we pull off one child, all the other come out of the main form, and when we click re restore button they also come off. :-) – NaN May 15 '13 at 01:16
  • @EASI declare FDragging as a class var and your problem is solved – iamjoosy May 15 '13 at 12:41
  • @EASI Yes, apparently `WM_WINDOWPOSCHANGED` is send to all other forms too... See edit. – NGLN May 15 '13 at 22:13
  • @EASI if you add mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); after the last line in TForm3.CreateParams then you have a Lamborghini – iamjoosy May 16 '13 at 16:20
  • Did not noticed difference, what should happened? :-/ – NaN May 17 '13 at 00:49
  • @EASI, well if you drag the MDI child out of the main form it is recreated and looses the "dragged state" and hence cannot be dragged outside the main form without clicking the title bar again. By issuing a mouse down event after the MDI window was recreated you can continue to drag the window outside the main form. – iamjoosy May 17 '13 at 08:11
  • How, ok, nice. But it did not worked with me, because the form changed it's position once it came out the main form, so the mouse leaves from the title bar. – NaN May 17 '13 at 19:15
  • @EASI - right, you need to tweak NGNL's code a bit to position the form correctly once it is out of the main form. – iamjoosy May 18 '13 at 02:04
  • I am thinking about repositioning the mouse back to the title bar :) – NaN May 18 '13 at 18:46
  • I do not understand why I get "Acces Violation" when I move the child to outside the MDI form... – NaN May 18 '13 at 19:17