zoukankan      html  css  js  c++  java
  • 关于 Delphi 中窗体的停靠

      对于停靠技术,网络上已有大篇的文件在述说。比较:高级停靠(Dock)技术的实现 ,这个是实现最复杂的(个人认为)。当然,我所使用的方法是参考了 Using the TDockTabSet component by Jeremy North . 这个方法是使用了自Delphi2005之后出现的TDockTabSet控件,对于其使用方法,有兴趣的朋友可以在网上搜索下。

      OK,下面来看下效果

     

    接下来,就要到代码了。哈哈,大家关心的可能就是这个。不过在这之前你还是先把上面的那个“Using the TDockTabSet component by Jeremy North ”理解下.

    代码实现其实很简单,我这里主要是使用接口及类封装

    先看下接口部分

    itf

    IDockForm

        这个就是需要被显示的窗体需实现的接口。其实接口的方法,属性有些窗体本身的方法,属性已经实现了,必要的是(你只需要把下面的部分代码抄过去就OK了)

    procedure TForm12.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      ManualFloat(Rect(0, 0, 0, 0));
      Action := caFree;
    end;

    procedure TForm12.FormStartDock(Sender: TObject;
      var DragObject: TDragDockObject);
    begin
      DragObject := TDragDockObjectEx.Create(Self);
      DragObject.Brush.Color := clAqua;
    end;

    function TForm12.GetDockSite: TWinControl;
    begin
      Result := FDockSite;
    end;

    function TForm12.ManualDock(NewDockSite: TWinControl; DropControl: TControl;
      ControlSide: TAlign): Boolean;
    begin
      Result := inherited ManualDock(NewDockSite, DropControl, ControlSide);
    end;

    procedure TForm12.SetBorderSytle(const Value: TFormBorderStyle);
    begin
      if BorderStyle <> Value then
        BorderStyle:=Value;
    end;

    procedure TForm12.SetDockSite(const Value: TWinControl);
    begin
      FDockSite := Value;
    end;

    procedure TForm12.SetDragKind(const Value: TDragKind);
    begin
      if DragKind <> Value then
        DragKind:=Value;
    end;

    procedure TForm12.SetDragMode2(const Value: TDragMode);
    begin
      if DragMode <> Value then
        DragMode:=Value;
    end;

    IDockSite , IDockManagenmnet

    这两个接口无需你来实现,它们是用来管理停靠和实现停靠位置的。

    原理

        首先创建的IDockManagenmnet 根据停靠的方位TDockSiteAlign,来创建停靠点IDockSite,有了停靠点就可以添加停靠窗体IDockForm了。

    1、创建 DockManagenment

    image

    2、

    image

    3、

    image

    =============================代码实现部分(20100410放出)======================================

    1、FunctionLibrary.UIDApi.Dock.pas 接口声明

    { --------------------------------窗体停止支持接口函数库概述--------------------------------
      CreateTime  : 2009-10-11
      Platform    : Windows 7 (7600.16385.090713-1255) 简体中文旗舰版
      IDE         : Embarcadero Delphi 2010 Version 14.0.3513.24210
      Description : 函数库(FunctionLibrary.*.pas)是一些常函数单元文件,基于win7及
                    RAD2010的基础上开发,可能存在向下兼容的问题.
                    关于单元内变量,常量,类型及函数、过程的定义以"组"为标准,即作为同
                    一处理函数的数据定义在一起.
      Example     :
    }
    unit Core.Dock;

    interface
    uses
      Forms,Controls,Classes;
    type
      TDockSiteAlign = (dsaLeft,dsaBottom,dsaRight);

      IDockForm = interface
        ['{FFE9B72A-EEBD-4201-9346-98D513F0E207}']
        procedure SetBorderSytle(const Value:TFormBorderStyle);
        property  BorderStyle:TFormBorderStyle write SetBorderSytle;
        procedure SetDragKind(const Value:TDragKind);
        property  DragKind:TDragKind write SetDragKind;
        procedure SetDragMode2(const Value:TDragMode);
        property  DragMode:TDragMode write SetDragMode2;
        function  GetDockSite:TWinControl;
        procedure SetDockSite(const Value:TWinControl);
        property  DockSite:TWinControl read GetDockSite write SetDockSite;
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure FormStartDock(Sender: TObject; var DragObject: TDragDockObject);
        function ManualDock(NewDockSite: TWinControl; DropControl: TControl = nil;
          ControlSide: TAlign = alNone): Boolean;
        procedure Show;
        procedure Close;
      end;

      IDockSite = interface
        ['{CDD2B1D8-63AE-494A-85A1-768D34D970A4}']
        function AddDockForm(const DockForm:IDockForm):Boolean;
        function GetVisible:Boolean;
        procedure SetVisible(const Value:Boolean);
        property Visible:Boolean read GetVisible write SetVisible;
        function GetWidth:Integer;
        procedure SetWidth(const Value:Integer);
        property Width:Integer read GetWidth write SetWidth;
        procedure SetAlign(const Value:TDockSiteAlign);
        property Align:TDockSiteAlign write SetAlign;
      end;

      IDockManagemnet = interface
        ['{3754DE0D-425B-4A43-AF02-616A1A5C46EC}']
        function AddDockSite(const Align:TDockSiteAlign):IDockSite;
        function GetDockSite(const Align:TDockSiteAlign):IDockSite;
      end;

    const
      DockFormGUID:TGUID='{FFE9B72A-EEBD-4201-9346-98D513F0E207}';

    implementation

    end.

    2、FunctionLibrary.UIDApi.Impl.pas 接口实现

    { --------------------------------窗体停止支持主程序实现函数库概述--------------------------------
      CreateTime  : 2009-10-11
      Platform    : Windows 7 (7600.16385.090713-1255) 简体中文旗舰版
      IDE         : Embarcadero Delphi 2010 Version 14.0.3513.24210
      Description : 函数库(FunctionLibrary.*.pas)是一些常函数单元文件,基于win7及
                    RAD2010的基础上开发,可能存在向下兼容的问题.
                    关于单元内变量,常量,类型及函数、过程的定义以"组"为标准,即作为同
                    一处理函数的数据定义在一起.
      Example     :
    }
    unit Core.Dock.Impl;

    interface

    uses
      FunctionLibrary.UIDApi.Dock, Classes, Controls,
      DockTabSet, ExtCtrls, Tabs, ComCtrls, Types, SysUtils;

    type

      TDockSiteControl = class
      strict private
        FOwner: IDockSite;
        FDockTabSet: TDockTabSet;
        FDockSplitter: TSplitter;
        FDockPanel: TPanel;
        procedure SetDockPanel(const Value: TPanel);
        procedure SetDockSplitter(const Value: TSplitter);
        procedure SetDockTabSet(const Value: TDockTabSet);
      public
        constructor Create(const AOwner: IDockSite);
        destructor Destroy; override;
        property DockTabSet: TDockTabSet read FDockTabSet write SetDockTabSet;
        property DockPanel: TPanel read FDockPanel write SetDockPanel;
        property DockSplitter: TSplitter read FDockSplitter write SetDockSplitter;
      end;

      TDockSite = class(TInterfacedObject, IDockSite)
      strict private
        FOwner: IDockManagemnet;
        FHost:TWinControl;
        FVisible: Boolean;
        FWidth: Integer;
        FDockSiteControl: TDockSiteControl;
        FAlign: TDockSiteAlign;
        FCount: Integer;
        FDockFormList: array of IDockForm;
        function GetDockFormIndex(const DockForm: IDockForm): Integer;
        // Events for inner controls
        procedure OnDockTabSetTabAdded(Sender: TObject);
        procedure OnDockPanelDockDrop(Sender: TObject; Source: TDragDockObject;
          X, Y: Integer);
        procedure OnDockPanelUnDock(Sender: TObject; Client: TControl;
          NewTarget: TWinControl; var Allow: Boolean);
        procedure OnDockPanelDockOver(Sender: TObject; Source: TDragDockObject;
          X, Y: Integer; State: TDragState; var Accept: Boolean);
        procedure OnDockTabSetDragDrop(Sender, Source: TObject; X, Y: Integer);
        procedure OnDockTabSetTabRemoved(Sender: TObject);

      strict protected
        function GetVisible: Boolean;
        function GetWidth: Integer;
        procedure SetVisible(const Value: Boolean);
        procedure SetWidth(const Value: Integer);
        procedure SetAlign(const Value: TDockSiteAlign);
      public
        constructor Create(const AOwner: IDockManagemnet; const Host: TWinControl);
        destructor Destroy; override;
        function AddDockForm(const DockForm: IDockForm): Boolean;
      end;

      TDockManagement = class(TInterfacedObject, IDockManagemnet)
      strict private
        FAOwner: TComponent;
        DockSiteList: array [TDockSiteAlign] of IDockSite;
      public
        constructor Create(AOwner: TComponent);
        destructor Destroy; override;
        function AddDockSite(const Align: TDockSiteAlign): IDockSite;
        function GetDockSite(const Align: TDockSiteAlign): IDockSite;
      end;

    implementation

    {$REGION '  TDockManagement '}
    { TDockManagement }

    function TDockManagement.AddDockSite(const Align: TDockSiteAlign): IDockSite;
    begin
      if Assigned(DockSiteList[Align]) then
        Exit(DockSiteList[Align]);
      Result := TDockSite.Create(Self, TWinControl(FAOwner));
      DockSiteList[Align] := Result;
      Result.Align := Align;
    end;

    constructor TDockManagement.Create(AOwner: TComponent);
    begin
      FAOwner := AOwner;
    end;

    destructor TDockManagement.Destroy;
    begin
      DockSiteList[dsaRight] := nil;
      DockSiteList[dsaLeft] := nil;
      DockSiteList[dsaBottom] := nil;
      FAOwner := nil;
      inherited;
    end;

    function TDockManagement.GetDockSite(const Align: TDockSiteAlign): IDockSite;
    begin
      Result := nil;
      if Assigned(DockSiteList[Align]) then
        Result := DockSiteList[Align];
    end;
    {$ENDREGION}
    { TDockSite }

    function TDockSite.AddDockForm(const DockForm: IDockForm): Boolean;
    var
      Len, Index: Integer;
    begin
      Result := False;
      Index := GetDockFormIndex(DockForm);
      if Index > -1 then
        Exit;
      DockForm.DockSite := FDockSiteControl.DockPanel;
      Len := Length(FDockFormList);
      if Len = 0 then
        SetLength(FDockFormList, 4)
      else if Len = FCount then
        SetLength(FDockFormList, Len * 2);
      FDockFormList[FCount] := DockForm;
      Inc(FCount);
      Result := True;
    end;

    constructor TDockSite.Create(const AOwner: IDockManagemnet;
      const Host: TWinControl);
    begin
      FDockSiteControl := TDockSiteControl.Create(Self);
      FOwner := AOwner;
      FHost:=Host;
      with FDockSiteControl do
      begin
        DockTabSet := TDockTabSet.Create(Host);
        with DockTabSet do
        begin
          Parent := TWinControl(Host);
          Visible := False;
          DockSite := False;
          ShrinkToFit := True;
          Style := tsModernTabs;
          DestinationDockSite := nil;
          OnDragDrop := OnDockTabSetDragDrop;
          OnTabRemoved := OnDockTabSetTabRemoved;
          OnTabAdded:=OnDockTabSetTabAdded;
        end;

        DockPanel := TPanel.Create(Host);
        with DockPanel do
        begin
          Parent := TWinControl(Host);
          Caption := '';
          Visible := False;
          Width := 0;
          BevelOuter := bvNone;
          DockSite := True;
          OnDockDrop := OnDockPanelDockDrop;
          onDockOver := OnDockPanelDockOver;
          OnUnDock := OnDockPanelUnDock;
        end;
        DockTabSet.DestinationDockSite := DockPanel;

        DockSplitter := TSplitter.Create(Host);
        with DockSplitter do
        begin
          Parent := TWinControl(Host);
          Visible := False;
          Width := 4;
        end;
      end;
    end;

    destructor TDockSite.Destroy;
    var
      Item: IDockForm;
    begin
      for Item in FDockFormList do
        if Assigned(Item) then
          Item.Close;
      SetLength(FDockFormList, 0);
      FDockSiteControl.Free;
      FOwner := nil;
      FHost:=nil;
      inherited;
    end;

    procedure TDockSite.OnDockTabSetTabAdded(Sender: TObject);
    begin
      FDockSiteControl.DockTabSet.Visible:=True;
    end;

    function TDockSite.GetDockFormIndex(const DockForm: IDockForm): Integer;
    var
      i: Integer;
    begin
      Result := -1;
      for i := 0 to FCount - 1 do
        if FDockFormList[i] = DockForm then
          Result := i;
    end;

    function TDockSite.GetVisible: Boolean;
    begin
      Result := FVisible;
    end;

    function TDockSite.GetWidth: Integer;
    begin
      Result := FWidth;
    end;

    procedure TDockSite.OnDockPanelDockDrop
      (Sender: TObject; Source: TDragDockObject; X, Y: Integer);
    begin
      with FDockSiteControl do
      begin
        if not DockPanel.Visible then
          DockPanel.Visible:=True;
        case FAlign of
          dsaLeft, dsaRight:
            begin
              if DockPanel.Width = 0 then
                DockPanel.Width := FWidth;
            end;
          dsaBottom:
            begin
              if DockPanel.Height = 0 then
                DockPanel.Height := FWidth;
            end;
        end;
        case FAlign of
          dsaBottom:
            begin
              DockPanel.Top:=DockTabSet.Top - DockPanel.Height;
              DockSplitter.Top:=DockPanel.Height - 4;
            end;
          dsaLeft:
            begin
              DockPanel.Left:=DockTabSet.Width;
              DockSplitter.Left:=DockPanel.Width + DockPanel.Left;
            end;
          dsaRight:
            begin
              DockPanel.Left:=DockTabSet.Left - DockPanel.Width;
              DockSplitter.Left:=DockPanel.Left - 4;
            end;
        end;
        DockSplitter.Visible := True;
      end;
    end;

    procedure TDockSite.OnDockPanelDockOver
      (Sender: TObject; Source: TDragDockObject; X, Y: Integer; State: TDragState;
      var Accept: Boolean);
    var
      lRect: TRect;
    begin
      Accept := Supports(Source.Control, DockFormGUID);
      if Accept then
      begin
        with FDockSiteControl do
        begin
          case FAlign of
            dsaLeft:
              begin
                lRect.TopLeft := DockPanel.ClientToScreen(Point(0, 0));
                lRect.BottomRight := DockPanel.ClientToScreen(Point(150,DockPanel.Height));
              end;
            dsaBottom:
              begin
                lRect.TopLeft := DockPanel.ClientToScreen(Point(0, 0));
                lRect.BottomRight := DockPanel.ClientToScreen(Point(DockPanel.Width,-150));
              end;
            dsaRight:
              begin
                lRect.TopLeft := DockPanel.ClientToScreen(Point(-150,0));
                lRect.BottomRight := DockPanel.ClientToScreen(Point(0 ,DockPanel.Height));
              end;
          end;
        end;
        Source.DockRect := lRect;
      end;
    end;

    procedure TDockSite.OnDockPanelUnDock(Sender: TObject; Client: TControl;
      NewTarget: TWinControl; var Allow: Boolean);
    begin
      with FDockSiteControl do
      begin
        if DockPanel.DockClientCount = 1 then
        begin
          case FAlign of
            dsaLeft, dsaRight:
              DockPanel.Width := 0;
            dsaBottom:
              DockPanel.Height := 0;
          end;
          DockSplitter.Visible := False;
        end;
      end;
    end;

    procedure TDockSite.OnDockTabSetDragDrop(Sender, Source: TObject;
      X, Y: Integer);
    begin
      FDockSiteControl.DockTabSet.Visible := True;
    end;

    procedure TDockSite.OnDockTabSetTabRemoved(Sender: TObject);
    begin
      FDockSiteControl.DockTabSet.Visible :=
        FDockSiteControl.DockTabSet.Tabs.Count > 0;
    end;

    procedure TDockSite.SetAlign(const Value: TDockSiteAlign);
      procedure SetControlAlign(const Alg: TAlign);
      begin
        with FDockSiteControl do
        begin
          with DockTabSet do
          begin
            Align := Alg;
            case Alg of
              alBottom:
                begin
                  TabPosition := tpBottom;
                  DockPanel.Top:=Top - DockPanel.Height;
                  DockSplitter.Top:=DockPanel.Height - 4;
                end;
              alLeft:
                begin
                  TabPosition := tpLeft;
                  DockPanel.Left:=Width;
                  DockSplitter.Left:=DockPanel.Width + DockPanel.Left;
                end;
              alRight:
                begin
                  TabPosition := tpRight;
                  DockPanel.Left:=Left - DockPanel.Width;
                  DockSplitter.Left:=DockPanel.Left - 4;
                end;
            end;
            DockPanel.Align := Alg;
            DockSplitter.Align := Alg;
          end;
        end;
      end;

    begin
      if FAlign <> Value then
        FAlign := Value;
      with FDockSiteControl do
      begin
        case Value of
          dsaLeft:
            begin
              DockTabSet.Width := 25;
              SetControlAlign(alLeft);
            end;
          dsaBottom:
            begin
              DockTabSet.Height := 25;
              DockPanel.Height := 0;
              SetControlAlign(alBottom);
            end;
          dsaRight:
            begin
              DockTabSet.Width := 25;
              SetControlAlign(alRight);
            end;
        end;
      end;
    end;

    procedure TDockSite.SetVisible(const Value: Boolean);
    begin
      if FVisible <> Value then
      begin
        FVisible := Value;
        with FDockSiteControl do
        begin
          DockTabSet.Visible := Value;
          DockPanel.Visible := Value;
    //      DockSplitter.Visible := Value;
        end;
      end;
    end;

    procedure TDockSite.SetWidth(const Value: Integer);
    begin
      if FWidth <> Value then
        FWidth := Value;
    end;
    {$REGION '  TDockSiteControl '}
    { TDockSiteControl }

    constructor TDockSiteControl.Create(const AOwner: IDockSite);
    begin
      FOwner := AOwner;
    end;

    destructor TDockSiteControl.Destroy;
    begin
      FOwner := nil;
      if Assigned(FDockPanel) then
        FDockPanel.Free;
      if Assigned(FDockTabSet) then
        FDockTabSet.Free;
      if Assigned(FDockSplitter) then
        FDockSplitter.Free;
      inherited;
    end;

    procedure TDockSiteControl.SetDockPanel(const Value: TPanel);
    begin
      FDockPanel := Value;
    end;

    procedure TDockSiteControl.SetDockSplitter(const Value: TSplitter);
    begin
      FDockSplitter := Value;
    end;

    procedure TDockSiteControl.SetDockTabSet(const Value: TDockTabSet);
    begin
      FDockTabSet := Value;
    end;
    {$ENDREGION}

    end.

  • 相关阅读:
    python后端面试题
    Django模块
    centos 6.x下jira显示饼图乱码解决方法
    Confluence与Jira安装及后期迁移问题记录
    SaltStack安装部署
    jumpserver跳板机(堡垒机)安装
    Python之Web前端Ajax
    python3.6下pycharm连接mysql
    Mac下安装SecureCRT客户端并激活
    Python模块之paramiko
  • 原文地址:https://www.cnblogs.com/goldli/p/1590562.html
Copyright © 2011-2022 走看看