• 014.Delphi插件之QPlugins,MDI窗口


    不知道为什么,这个DEMO编译出来报错,运行不了,在QDAC群里问了一下也没人响应。

    效果如下

    主程序代码如下

    unit Frm_Main;
    
    interface
    
    uses
      Winapi.Windows,
      Winapi.Messages,
      System.SysUtils,
      System.Variants,
      System.Classes,
      Vcl.Graphics,
      Vcl.Controls,
      Vcl.Forms,
      Vcl.Dialogs,
      Vcl.Menus,
      QPlugins,
      qplugins_params,
      qplugins_formsvc,
      qplugins_vcl_formsvc,
      qplugins_loader_lib;
    
    { 注意使用 MDI 子窗体做为插件,宿主和插件都必需同时引用rtl/vcl运行时包 }
    
    type
      TForm_Main = class(TForm)
        MainMenu1: TMainMenu;
        File1: TMenuItem;
        procedure FormCreate(Sender: TObject);
        procedure File1Click(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
      private
        { Private declarations }
        FOpenChildren: array of IQFormService;
        procedure DoFormClosed(AForm: IQFormService; var Action: TCloseAction);
        procedure DoFormFree(AForm: IQFormService);
      public
        { Public declarations }
      end;
    
    var
      Form_Main: TForm_Main;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm_Main.DoFormClosed(AForm: IQFormService; var Action: TCloseAction);
    var
      I: Integer;
    begin
      // 方法1:设置Action为caFree,然后由DoFormFree事件来处理清理服务
      // Action := caFree;
      // 方法2:直接释放引用就可以,优点是不用处理 OnFree 事件了
      for I := 0 to High(FOpenChildren) do
      begin
        if FOpenChildren[I] = AForm then
        begin
          Delete(FOpenChildren, I, 1);
          Break;
        end;
      end;
    end;
    
    procedure TForm_Main.DoFormFree(AForm: IQFormService);
    var
      I: Integer;
    begin
      // 直接释放引用就可以
      for I := 0 to High(FOpenChildren) do
      begin
        if FOpenChildren[I] = AForm then
        begin
          Delete(FOpenChildren, I, 1);
          Break;
        end;
      end;
    end;
    
    // 菜单_新建
    procedure TForm_Main.File1Click(Sender: TObject);
    var
      AService: IQFormService;
      // 窗体事件
      AEvents: TQFormEvents;
    begin
      if Supports(PluginsManager.ByPath('/Services/Forms/MDI/MDITest'), IQFormService, AService) then
      begin
        // 设置窗体事件
        FillChar(AEvents, SizeOf(AEvents), 0);
        // 替换窗体的关闭和释放事件
        AEvents.OnClose := DoFormClosed;
        AEvents.OnFree := DoFormFree;
        AService.HookEvents(AEvents);
        AService.Show;
        // FOpenChildren数组长度+1,为了添加一个AService
        SetLength(FOpenChildren, Length(FOpenChildren) + 1);
        FOpenChildren[High(FOpenChildren)] := AService;
      end;
    end;
    
    procedure TForm_Main.FormClose(Sender: TObject; var Action: TCloseAction);
    var
      I: Integer;
      AEvents: TQFormEvents;
    begin
      // 在直接关闭前,要先移除事件关联,否则在服务释放时,回调DoFormFree时会出错
      FillChar(AEvents, SizeOf(AEvents), 0);
      // 遍历移除替换的窗体事件
      for I := 0 to High(FOpenChildren) do
      begin
        FOpenChildren[I].HookEvents(AEvents);
      end;
      // 清空
      SetLength(FOpenChildren, 0);
    end;
    
    // 创建
    procedure TForm_Main.FormCreate(Sender: TObject);
    begin
      with PluginsManager do
      begin
        // 加载同目录下dll文件
        Loaders.Add(TQDLLLoader.Create(ExtractFilePath(Application.ExeName), '.dll'));
        // 启动服务
        Start;
      end;
    end;
    
    end.

    DLL代码如下

    unit Frm_Mdi;
    
    
    interface
    
    uses
      Winapi.Windows,
      Winapi.Messages,
      System.SysUtils,
      System.Variants,
      System.Classes,
      Vcl.Graphics,
      Vcl.Controls,
      Vcl.Forms,
      Vcl.Dialogs;
    
    type
      TForm_Mdi = class(TForm)
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form_Mdi: TForm_Mdi;
    
    implementation
    
    uses
      QPlugins,
      qplugins_vcl_formsvc;
    {$R *.dfm}
    
    initialization
    
    // 注册一个单实例服务
    RegisterFormService('/Services/Forms/MDI', 'MDITest', TForm_Mdi);
    
    finalization
    
    // 注销
    UnregisterServices('/Services/Forms/MDI', ['MDITest']);
    
    end.
  • 相关阅读:
    双显示器或更多个显示器,能分别设置不同的壁纸吗?
    二叉排序树
    如何将一棵树转化为对应的二叉树
    【例2.1】使用成员函数的实例
    [例1.10]使用setw设置输出宽度的例子
    python学习(三)-面向对象
    git 笔记
    python学习笔记(二)
    python基础语法
    fiddler
  • 原文地址:https://www.cnblogs.com/tianpan2019/p/11504574.html
Copyright © 2020-2023  润新知