limelect 48 Posted August 26, 2020 (edited) Using D10.2.3 function TForm1.GxOtaGetCurrentModule: IOTAModule; var ModuleServices: IOTAModuleServices; begin ModuleServices := BorlandIDEServices as IOTAModuleServices; Assert(Assigned(ModuleServices)); Result := ModuleServices.CurrentModule; end; function TForm1.GxOtaGetFormEditorFromModule(const Module: IOTAModule): IOTAFormEditor; var i: Integer; Editor: IOTAEditor; FormEditor: IOTAFormEditor; begin Result := nil; if not Assigned(Module) then Exit; for i := 0 to Module.GetModuleFileCount - 1 do begin Editor := GxOtaGetFileEditorForModule(Module, i); if Supports(Editor, IOTAFormEditor, FormEditor) then begin Assert(not Assigned(Result)); Result := FormEditor; // In order to assert our assumptions that only one form // is ever associated with a module, do not call Break; here. end; end; end; function TForm1.GxOtaGetFileEditorForModule(Module: IOTAModule; Index: Integer): IOTAEditor; begin Assert(Assigned(Module)); Result := Module.GetModuleFileEditor(Index); end; procedure TForm1.Button2Click(Sender: TObject); var CurrentModule: IOTAModule; CurrentForm: IOTAFormEditor; lComponent: IOTAComponent; begin CurrentModule := GxOtaGetCurrentModule; Assert(Assigned(CurrentModule)); CurrentForm := GxOtaGetFormEditorFromModule(CurrentModule); if CurrentForm.GetSelCount > 0 then lComponent := CurrentForm.GetSelComponent(0) else lComponent := CurrentForm.GetRootComponent; if not lComponent.IsTControl then begin ShowMessage('The Component of Selected is not Container Control!'); exit; end; //CurrentForm.GetSelComponent(0).GetComponentType; Label2.Caption:=lComponent.GetComponentType; <<<<< Tpanel or Tform Label3.Caption:= CurrentForm.FileName; <<< file.dfm // CurrentForm.CreateComponent(lComponent, 'TADOtable', 0, 0, 50, 50); <<<< This is OK ///THIS IS WHERE THE ERROR IS CurrentForm.CreateComponent({CurrentForm.GetSelComponent(0)}lComponent, 'TLabel', 0, 0, 50, 50);<<<< This is an ERROR end; ERROR = Class TLabel is not applicable to this module Any help? Edited August 26, 2020 by limelect Share this post Link to post
David Hoyle 68 Posted August 26, 2020 I assume that manually dropping a TLabel onto the component works? Do you have a test case project that shows this error so we can debug and investigate? Share this post Link to post
limelect 48 Posted August 26, 2020 (edited) @David Hoyle I did not want to bother you However i will send you the source. I used an old D6 project called ComponentSearch the project called cs very simple. It has a few pas so it is useless to put it here Thanks Edited August 26, 2020 by limelect Share this post Link to post
limelect 48 Posted August 27, 2020 (edited) I would like to thanks @David Hoyle for his personal communication. It seems that "CurrentForm.CreateComponent" in another variation too give this ERROR "Class TLabel is not applicable to this module". Although the variables are correct. Using TADOtable instead of Tlabel is working. Any idea? Edited August 27, 2020 by limelect Share this post Link to post
limelect 48 Posted August 30, 2020 Delphi and Embarcadero. "CurrentForm.CreateComponent" works on D7 !!! it creates the component. Can someone explain why? Is it a bug in Delphi? Share this post Link to post
limelect 48 Posted September 6, 2020 I finally have a solution with the help of GEXPERT @dummzeuch source It says "// If this starts crashing try IDesigner.CreateComponent" So I did var IDs: IDesigner; change create component to ids := (CurrentForm as INTAFormEditor).FormDesigner; if Assigned(IDs) then IDs.CreateComponent(TComponentClass( Tlabel),GxOtaGetNativeComponent(lComponent),0,0,50,50) ; I hop i did OK Any further help will be appritiated For me, it worked on D10.2.3 this is what I needed. 2 Share this post Link to post
David Hoyle 68 Posted September 6, 2020 @limelect Just had a thought and tried the following and had some success... but need to go get something to eat... You must use a Package and that package must be set to Design Time only. Doing that I've managed to insert a TLabel and TEdit successfully but the add-in crashed exiting the IDE, something to do with the form I was using... need food thought 🙂 Share this post Link to post
David Hoyle 68 Posted September 6, 2020 @limelect Just checked that error I was getting has nothing to do with the plug-in, the IDE does it all on its own without the plug-in being invoked but guess what, the exact same code in another session fails. Share this post Link to post
David Hoyle 68 Posted September 6, 2020 Okay, I'm leaning towards the issue being FMX verse VCL. I iterated all the packages below and picked out all the components and found duplicates between the frameworks. So I think GetClass() is looking up in FMX instead of VCL. Since it's now failing, selecting a VCL only component does nothing as GetClass() cannot find the component (which does not exist in FMX). Getting a bit late now but I know that on occasions the IDE prompts you to select which framework you are using (FMX or VCL) and I need to find out how we influence this determination (starting a new VCL app didn't work but then again I didn't save it). Share this post Link to post
David Hoyle 68 Posted September 6, 2020 Well I think GetClass() is finding FMX controls not VCL ones which is why this is not working (despite the designer type and framework type being VCL). Had enough for now. Might look later in the week if time permits. Share this post Link to post
limelect 48 Posted September 7, 2020 (edited) @David Hoyle if I use this IDs.CreateComponent(TComponentClass( Tlabel),GxOtaGetNativeComponent(lComponent),0,0,50,50) ; Tlabel not as a string it needs USES to work. Using TADOtable need USES. But it works. So I tried GetClass instead and it got me back to the ERROR; It seems that the main problem is the difference between VISUAL AND NON VISUAL. Since TADOtable workers in any configuration but Tlabel maks the ERROR 'not applicable to this module' So the question is if not this module then which one. In my case, I use the dfm/pas source Label3.Caption:= CurrentForm.FileName; <<<< DFM CurrentForm is derived from CurrentModule. Label4.Caption:=CurrentModule.FileName; <<<< PAS The objective is to place ANY component on a control be Form, Panel, or else. I did not get to the point of differentiating between VCL and FMX. Right now I am trying only to use VCL. And lastly the original source workers on D7 so there is a difference between the Delphi version although the sources (DesignIntf and more) seem to be the same. Edited September 7, 2020 by limelect Share this post Link to post
limelect 48 Posted September 7, 2020 (edited) @David Hoyle You made me think and I just found that 1. It works on FMX 2 I did not do an extensive check but it seems to work with VISUAL and NON VISUAL. So why the difference? Edited September 7, 2020 by limelect Share this post Link to post
limelect 48 Posted September 10, 2020 Thanks, everybody. After trying to solve my problem with ALL "CreateComponent" (tried a few) it seems that I do not have a solution for VCL. I hope maybe @David Hoyle will find a solution? So for my last question for this is it possible to distinguish , when I have a component name as a string, if it is for VCL of FMX. I know that fact from the registry but that not good enough since NOT all components are written there. The components list names are taken from PackageServices := BorlandIDEServices as IOTAPackageServices; Share this post Link to post
Remy Lebeau 1396 Posted September 10, 2020 (edited) On 9/6/2020 at 11:57 PM, limelect said: And lastly the original source workers on D7 FMX didn't exist yet in D7, there was only VCL. 7 hours ago, limelect said: So for my last question for this is it possible to distinguish , when I have a component name as a string, if it is for VCL of FMX. Not easily, and not always. If a component's class name is fully qualified, you could look at the prefix to see if it begins with 'Vcl.' vs 'Fmx.' but that only works for components that are distinctly VCL or FMX, it will not work for classes that are shared by both frameworks, ie classes whose qualified names begin with 'System.', 'Data.', 'Xml.', etc. Otherwise, you could drill into each component's RTTI to see if they derive from Vcl.Controls.TControl vs Fmx.Controls.TControl, but again that only works for VISUAL components that are distinctly VCL vs FMX, but will not work for NON-VISUAL components that derive from TComponent and not from TControl. And, of course, the situation may get more complicated in cases where users (despite being told not to) decide to mix VCL and FMX together into a single project. Edited September 10, 2020 by Remy Lebeau Share this post Link to post
limelect 48 Posted September 10, 2020 Thanks, @Remy Lebeau I thought it will be complicated. Do you have an idea why "CreateComponent" does not work on VCL? Is it a Delphi bug? Share this post Link to post
David Hoyle 68 Posted September 11, 2020 I need to go back over this at the weekend (no time at the moment due to the day job) but I seem to remember one of the techniques I tried required a fully qualified name which I think we can build from enumerating the packages and their components in the IDE. 1 Share this post Link to post
limelect 48 Posted September 11, 2020 (edited) @David Hoyle Unfortunately I do not understand "fully qualified name". An example of "fully qualified name"? What I get from the IDE is a component name as a string. Is there another way? The successful "CreateComponent" uses a component name, not a string, that needed a USES, which is not good. Ok i read the explanation So what you mean is to go from "TStream" to System.Classes.TStream and then use that? Edited September 11, 2020 by limelect Share this post Link to post
David Hoyle 68 Posted September 11, 2020 @limelect I mean Unit.Component or perhaps event Package.Unit.Component. At some point in the work I did last Saturday when trying to find a solution for you, I'm positive one of the solutions accepted this format as a string. I'll try again tomorrow. Share this post Link to post
limelect 48 Posted September 11, 2020 @David Hoyle I did try 'Vcl.StdCtrls.TLable' it did not make any mistake but did not create a component. All the time I am trying with my base instruction CurrentForm.CreateComponent(lComponent, 'Vcl.StdCtrls.TLabel', 0, 0, 50, 50); << this did not make a mistake. however, the list of components is like TLabel and not Vcl.StdCtrls.TLabel. The last few hours I tried from string to class and going from there but did not succeed function FindAnyClass2(const Name: string): TClass; >> this is ok but from here to IOTAComponent; i am again stack. var 😄 TClass; ctx: TRttiContext; typ: TRttiType; begin ctx := TRttiContext.Create; typ := ctx.FindType(Name); if (typ <> nil) and (typ.IsInstance) then c := typ.AsInstance.MetaClassType; result:=c; ctx.Free; end; I really do not have a solution. I am an expert in real-time processes. Making software for big companies but am not an expert in EXPERT. Share this post Link to post
Remy Lebeau 1396 Posted September 11, 2020 (edited) Not sure if this will help, but you might try calling ActivateClassGroup(TControl) before calling CreateComponent() to create a TControl-derived component. At least in DFM streaming, ActivateClassGroup() can be used to limit the class types that are looked at, to avoid ambiguities with VCL and FMX classes of the same name. Edited September 11, 2020 by Remy Lebeau 1 Share this post Link to post
David Hoyle 68 Posted September 12, 2020 Thanks @Remy Lebeau, I will check this out today. 1 Share this post Link to post
David Hoyle 68 Posted September 12, 2020 Alas @Remy Lebeau's suggestion has not worked in the 2 scenarios I have. I will pick this up again later today or tomorrow as I'm sure I had some part of it working with qualified names last week. 1 Share this post Link to post
David Hoyle 68 Posted September 12, 2020 @Remy Lebeau you were right, I just didn't call it properly. The below code works for me in 10.4.1... // Set the control framework ActivateClassGroup(Vcl.Controls.TControl); // <= THIS FIXES IT!!!!!!!!! // Get the generic form editor for the current module Module := TACTFUtilities.CurrentModule; FormEditor := TACTFUtilities.FormEditor(Module); // Get the simple class name from a dropdown, i.e. TLabel, TButton, TEdit, etc strClassName := edtComponentClassName.Text; Delete(strClassName, Pos('=', strClassName), strClassName.Length); // Insert the component with the selected component parent If Assigned(FormEditor) Then Begin Component := FormEditor.GetCreateParent; Component := FormEditor.CreateComponent( Component, strClassName, 10, 10, 50, 28 ); FormEditor.MarkModified; End; Share this post Link to post
limelect 48 Posted September 12, 2020 (edited) @David Hoyle @Remy Lebeau that did it I just added ActivateClassGroup(Vcl.Controls.TControl); @David Hoyle I could not tell everybody how much you help. Thank you very much. And to you @Remy Lebeau that did it thanks. What i did is adding if ExtractFileExt(CurrentForm.FileName)='.dfm' then ActivateClassGroup(VCL.Controls.TControl); So i have it for both Now @David Hoyle when you write the BLOG plz notify me. Thanks. It was a long road for both of us. Edited September 12, 2020 by limelect Share this post Link to post