如何将 MDI 子窗口从主窗体中拖出?

3
我希望创建一个带有自己任务栏的MDI应用程序,以便用户可以快速访问要前置的子窗口。然后我想到了一个用户使用两个或多个显示器的想法,他可以将一个子窗口从我的应用程序的主窗体内部拖到外部,例如另一个监视器中。

如何实现?


1
你所描述的并不是一个MDI应用程序,因为我认为MDI并不会直接支持你需要的功能。相反,这是一个使用可停靠窗体的MDI应用程序。这种应用程序的典型Delphi示例就是Delphi IDE本身。阅读有关停靠的内容,这应该很常规。 - David Heffernan
3
Windows 7 增加了对 MDI 子窗口通过 ITaskbarList3 接口访问任务栏的支持。但是无法将 MDI 子窗口“拖出”到浮动窗口中。您可以创建停靠窗口,或将 MDI 内容移动到框架中,在需要时可以将其从 MDI 子窗体和浮动窗体之间重新父子化。 - Remy Lebeau
@DavidHeffernan,你测试了NGLN的答案吗?我指的就是那个,它完美地解决了我的问题!:-) - NaN
你如何判断用户想要拖动而不是调整位置?如果是 MDI,我会使用上下文菜单操作来实现。 - David Heffernan
我不理解。您如何确定用户想要将其转换为独立窗口而不仅仅是移动子窗口?或者您不再允许他们移动子窗口了吗? - David Heffernan
显示剩余5条评论
1个回答

4
也许这个多文档界面客户端表单的示例代码能够启发您:
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.

这非常有趣,它完成了工作!但我会稍微处理一下,因为当我们卸载一个子项时,所有其他子项都从主窗体中出现了,当我们单击重新还原按钮时它们也被移除了。 :-) - NaN
声明FDragging为类变量,你的问题就解决了。 - iamjoosy
@EASI 是的,显然 WM_WINDOWPOSCHANGED 也会发送到所有其他窗体...请参见编辑。 - NGLN
如果您在TForm3.CreateParams的最后一行后添加mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);,那么您就拥有了一辆兰博基尼。 - iamjoosy
没有注意到区别,应该发生了什么?:-/ - NaN
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接