From 2ef75319f9b3268a3304866cbbb165485570d545 Mon Sep 17 00:00:00 2001 From: Lucas Moura Belo Date: Tue, 22 Dec 2020 15:46:17 -0300 Subject: [PATCH 1/3] Delphi FMX wrappers registration --- Source/fmx/WrapDelphiFmx.pas | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Source/fmx/WrapDelphiFmx.pas diff --git a/Source/fmx/WrapDelphiFmx.pas b/Source/fmx/WrapDelphiFmx.pas new file mode 100644 index 00000000..5bd1b3b5 --- /dev/null +++ b/Source/fmx/WrapDelphiFmx.pas @@ -0,0 +1,23 @@ +unit WrapDelphiFmx; + +interface + +implementation + +uses + WrapDelphiTypes, + WrapDelphiClasses, + WrapDelphiWindows, + WrapFireDac, + WrapFmxTypes, + WrapFmxStdCtrls, + WrapFmxActnList, + WrapFmxComCtrls, + WrapFmxDialogs, + WrapFmxForms, + WrapFmxShapes, + WrapFmxLayouts, + WrapFmxScrollBox, + WrapFmxGrids; + +end. From 11b60f795535ba831805e64aa442e83db3c152ed Mon Sep 17 00:00:00 2001 From: Lucas Moura Belo Date: Tue, 22 Dec 2020 16:13:18 -0300 Subject: [PATCH 2/3] Creational mechanism for resourced and non-resourced FMX forms --- Source/fmx/WrapFmxForms.pas | 54 +++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/Source/fmx/WrapFmxForms.pas b/Source/fmx/WrapFmxForms.pas index 646bfd03..785346fc 100644 --- a/Source/fmx/WrapFmxForms.pas +++ b/Source/fmx/WrapFmxForms.pas @@ -5,7 +5,8 @@ interface uses - FMX.Forms, PythonEngine, WrapDelphiClasses, WrapFmxTypes, WrapFmxControls; + System.Classes, FMX.Forms, + PythonEngine, WrapFmxTypes, WrapDelphiClasses, WrapFmxControls; type TPyDelphiApplication = class(TPyDelphiComponent) @@ -23,7 +24,9 @@ TPyDelphiCommonCustomForm = class(TPyDelphiFmxObject) private function GetDelphiObject: TCommonCustomForm; procedure SetDelphiObject(const Value: TCommonCustomForm); + function HasFormRes(const AClass: TClass): boolean; public + function CreateComponent(AOwner: TComponent): TComponent; override; // Class methods class function DelphiObjectClass: TClass; override; // Properties @@ -88,7 +91,7 @@ TPyDelphiScreen = class(TPyDelphiComponent) implementation uses - WrapDelphi; + WrapDelphi, System.Types; { Register the wrappers, the globals and the constants } type @@ -153,6 +156,46 @@ procedure TPyDelphiApplication.SetDelphiObject(const Value: TApplication); { TPyDelphiCommonCustomForm } +function TPyDelphiCommonCustomForm.CreateComponent( + AOwner: TComponent): TComponent; +type + TCommonCustomFormClass = class of TCommonCustomForm; +var + LClass: TClass; + LFormClass: TCommonCustomFormClass; + LClassName: string; +begin + //if we have a subclass of our Form wrapper, then check if we can find a + //Delphi class that would have the same name as the Python class. + //This would allow Python to instanciate an existing Delphi form class, + //insted of only using a blank form. + if (ob_type <> PythonType.TheTypePtr) then begin + LClassName := string(ob_type.tp_name); + LClass := GetClass(LClassName); + if not Assigned(LClass) then + LClass := GetClass('T' + LClassName); + if Assigned(LClass) and LClass.InheritsFrom(TCommonCustomForm) then + LFormClass := TCommonCustomFormClass(LClass); + end else begin + //get de default form class + if DelphiObjectClass.InheritsFrom(TCommonCustomForm) then + LFormClass := TCommonCustomFormClass(DelphiObjectClass); + end; + + //if it's not a design form, so we create it as a non-resourced form, + //using the non-resourced constructor. + //if the Owner is TApplication, then we have to call its CreateForm method, + //otherwise we won't have a mian form defined, as the main form is the first + //created form. Of course, this is a concern only when Python controls all the + //GUI and calls Apllication.Run by itself. + if not HasFormRes(LFormClass) then + Result := LFormClass.CreateNew(AOwner) + else if (AOwner = Application) then + Application.CreateForm(LFormClass, Result) + else + Result := LFormClass.Create(AOwner); +end; + class function TPyDelphiCommonCustomForm.DelphiObjectClass: TClass; begin Result := TCommonCustomForm; @@ -163,6 +206,13 @@ function TPyDelphiCommonCustomForm.GetDelphiObject: TCommonCustomForm; Result := TCommonCustomForm(inherited DelphiObject); end; +function TPyDelphiCommonCustomForm.HasFormRes(const AClass: TClass): boolean; +begin + Result := FindResource( + FindResourceHInstance(FindClassHInstance(AClass)), + PChar(AClass.ClassName), PChar(RT_RCDATA)) <> 0; +end; + procedure TPyDelphiCommonCustomForm.SetDelphiObject( const Value: TCommonCustomForm); begin From 3027ed1ee225c9586f7c9feb8206912594a9f6fb Mon Sep 17 00:00:00 2001 From: Lucas Moura Belo Date: Tue, 22 Dec 2020 17:18:29 -0300 Subject: [PATCH 3/3] FMX form class validation --- Source/fmx/WrapFmxForms.pas | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Source/fmx/WrapFmxForms.pas b/Source/fmx/WrapFmxForms.pas index 785346fc..9e463e61 100644 --- a/Source/fmx/WrapFmxForms.pas +++ b/Source/fmx/WrapFmxForms.pas @@ -5,7 +5,7 @@ interface uses - System.Classes, FMX.Forms, + System.Classes, System.SysUtils, FMX.Forms, PythonEngine, WrapFmxTypes, WrapDelphiClasses, WrapFmxControls; type @@ -88,6 +88,8 @@ TPyDelphiScreen = class(TPyDelphiComponent) property DelphiObject: TScreen read GetDelphiObject write SetDelphiObject; end; + EInvalidFormClass = class(Exception); + implementation uses @@ -165,6 +167,11 @@ TCommonCustomFormClass = class of TCommonCustomForm; LFormClass: TCommonCustomFormClass; LClassName: string; begin + LFormClass := nil; + //get de default form class + if DelphiObjectClass.InheritsFrom(TCommonCustomForm) then + LFormClass := TCommonCustomFormClass(DelphiObjectClass); + //if we have a subclass of our Form wrapper, then check if we can find a //Delphi class that would have the same name as the Python class. //This would allow Python to instanciate an existing Delphi form class, @@ -176,12 +183,12 @@ TCommonCustomFormClass = class of TCommonCustomForm; LClass := GetClass('T' + LClassName); if Assigned(LClass) and LClass.InheritsFrom(TCommonCustomForm) then LFormClass := TCommonCustomFormClass(LClass); - end else begin - //get de default form class - if DelphiObjectClass.InheritsFrom(TCommonCustomForm) then - LFormClass := TCommonCustomFormClass(DelphiObjectClass); end; + if not Assigned(LFormClass) then + raise EInvalidFormClass.CreateFmt('Type %s is not a valid form class', [ + DelphiObjectClass.ClassName]); + //if it's not a design form, so we create it as a non-resourced form, //using the non-resourced constructor. //if the Owner is TApplication, then we have to call its CreateForm method,