イベントマネージャ【ソース編】

とりあえずソースから(2022/09/28 更新)。

unit NY_EventManager;

interface

uses System.SysUtils,System.Classes,System.Rtti, Vcl.Dialogs
    ,System.Generics.Defaults,System.Generics.Collections
 ;

{
==========
【使用法】
==========
・イベント情報配列の設定&SetEventでイベント登録
  ⇒ 個別に追加ならAddEventで。
・DoEventでイベント実行


------------------------------------------------------------------------------
■ SetEventの引数(TNYEventProc:イベント実行部と Array of String:イベント情報配列)
------------------------------------------------------------------------------
------------------------------------------------------------------------------
(サンプル)
------------------------------------------------------------------------------
const
//--------------------------------
//(イベント情報配列の設定)
//--------------------------------
_Event_BeforeEditorRunning = '_Event_BeforeEditorRunning';
_Event_BeforeEditorShow    = '_Event_BeforeEditorShow';
_Event_BeforeEditorClose   = '_Event_BeforeEditorClose';

EventStr:Array[0..2] of string =(_Event_BeforeEditorRunning
                                ,_Event_BeforeEditorShow
                                ,_Event_BeforeEditorClose
                                );

//-------------------
// (イベント実行部)
//-------------------
function TfrmScriptEditor.RunEvent(Sender:TObject;EventName:string;var Param:TNYEventParm):boolean;
begin
 //イベント実行
 Result:=False;   // False ⇒ 次のイベントを止めない

 RunScripts('',Param.Param[0].asString);
 Param.Result:=[NV_Script.Values['ScriptResult']];
end;

------------------------------------------------------------------------------
■ AddEventの引数(TNYEventRecレコード)
------------------------------------------------------------------------------
(TNYEventRecレコードのフィールド)
 ・EventName :string;       //イベント識別名:イベントを実行する際に必要となる
 ・OrderLevel:integer;      //イベント実行順:小さいものから実行される

 ・EventProc :TNYEventProc; //イベント実行部
  ※)TNYEventProc = reference to function(Sender:TObject;EventName:string;var Param:TNYEventParm):boolean;
  ※)TNYEventParm
      ⇒ TNYEventParm=record
      Param :Array of TValue;   // 参照)オープン配列パラメータ、
      Result:Array of TValue;   //      オープン配列コンストラクタ
     end;
}



//=========================================================
//=========================================================
type
 TNYEventParm=record
  Param :Array of TValue;   // 参照)オープン配列パラメータ、
  Result:Array of TValue;   //      オープン配列コンストラクタ
 end;

 //イベント実行の際の型:戻り値は次以降のイベントを実行させるかどうか
 TNYEventProc = reference to function(Sender:TObject;EventName:string;var Param:TNYEventParm):boolean;

 TNYEventRec=record
  EventName :string;       //イベント識別名:イベントを実行する際に必要となる
  OrderLevel:integer;      //イベント実行順:小さいものから実行される

  EventProc :TNYEventProc; //イベント実行部

  //以下 Function化、クラスメソッド化を検討
  procedure Init(aName:string);                           overload;
  procedure Init(aName:string;aEventProc:TNYEventProc);   overload;
  function  Init(aName:string;Order:integer):TNYEventRec; overload;

 end;


 TNYEventManager=class
  private
   FEventList     :TList<TNYEventRec>;
   FEventListIndex:TList<integer>;            //ソート用に
   FOnEvent       :TNYEventProc;              //イベント実行部

  public

   constructor Create;
   destructor  Destroy; override;

   procedure SetEvent(EV:TNYEventProc;EventStr:Array of String);
   function  AddEvent(Val:TNYEventRec):integer;

   procedure DoEvent(Sender:TObject;EventName:string;var Param:TNYEventParm);  overload;
   procedure DoEvent(Sender:TObject;EventName:string);                         overload;


  property OnEvent:TNYEventProc read FOnEvent write FOnEvent;

 end;


implementation


//=========================================================
//=========================================================
procedure TNYEventRec.Init(aName:string);
begin
 OrderLevel:=0;
 EventProc :=nil;

 EventName :=aName;
end;

procedure TNYEventRec.Init(aName:string;aEventProc:TNYEventProc);
begin
 Init(aName);
 EventProc:=aEventProc;
end;

function TNYEventRec.Init(aName:string;Order:integer):TNYEventRec;
begin
 with Result do begin
  EventName :=aName;
  OrderLevel:=Order;
  EventProc :=Self.EventProc;
 end;
end;


//=========================================================
//=========================================================
constructor TNYEventManager.Create;
begin
 FEventList     :=TList<TNYEventRec>.Create;
 FEventListIndex:=TList<integer>.Create;

 FOnEvent       :=nil;
end;

destructor TNYEventManager.Destroy;
begin
 inherited;

 FreeAndNil(FEventListIndex);
 FreeAndNil(FEventList);
end;


//=========================================================
//=========================================================
procedure TNYEventManager.SetEvent(EV:TNYEventProc;EventStr:Array of String);
var val:TNYEventRec;
    i:integer;
begin
 //--------------------
 // イベント先設定
 //--------------------
 val.Init('',EV);

 //---------------------------
 // イベントパラメータ設定
 //---------------------------
 for i:=Low(EventStr) to High(EventStr) do AddEvent(Val.Init(EventStr[i],0));
end;

function TNYEventManager.AddEvent(Val:TNYEventRec):integer;
begin
 Result:=FEventList.Add(Val);
end;

procedure TNYEventManager.DoEvent(Sender:TObject;EventName:string);
var Rt:TNYEventParm;
begin
 Rt.Param :=[];
 Rt.Result:=[];
 DoEvent(Sender,EventName,Rt);
end;

procedure TNYEventManager.DoEvent(Sender:TObject;EventName:string;var Param:TNYEventParm);
var Rt1,Rt2:TNYEventRec;
    i:integer;
begin
 //イベントリストインデックスをクリア
 FEventListIndex.Clear;

 //EventNameで抽出
 for i:=0 to FEventList.Count-1 do begin
  if FEventList[i].EventName=EventName then FEventListIndex.Add(i);
 end;

 //実行順番をソート
 FEventListIndex.Sort(TComparer<integer>.Construct(
   function(const Item1,Item2:integer):Integer
   begin
    Rt1:=FEventList[Item1];
    Rt2:=FEventList[Item2];

    //
    Result:=0;
    if Rt1.OrderLevel=Rt2.OrderLevel then exit;
    Result:=(Rt1.OrderLevel-Rt2.OrderLevel);
   end)
  );


 //実際にイベントを呼び出し
 for i:=0 to FEventListIndex.Count-1 do begin

  //Loop
  with FEventList[FEventListIndex[i]] do begin

   //OnEventプロパティが設定されている場合それを使用
   if Assigned(FOnEvent) then begin
    if not FOnEvent(Sender,EventName,Param) then break;
   end else begin
   //EventProcプロパティが設定されていない場合、TNYEventRecのEventProcを使用
    if Assigned(EventProc) then begin
     if not EventProc(Sender,EventName,Param) then break;
    end else begin
     //イベントが設定されていない場合はエラー
     ShowMessage('Error:TNYEventManager.DoEvent');
     exit;
    end;
   end;

  end; //End of With
 end; //End of Loop


end;



end.

解説は後日に追記します。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする