DelphiTheWorld 0 Posted November 7 Hello everybody, I met a problem with FMX component. I used a FMX frame to quickly put objects on it, add properties to change images on it and rotate them. In fact a quickly manner to build a component. After that to reuse it I decided to put it on a bpl packaqe and to install it. I open a fresh blank FMX project and move on the form the component (the famous frame) from the palette freshly added by the bpl package. When I'm in design time all the propertiues are well working but when I run it: the different properties are not working if I put on the form 2 times the same component and run it I have a warning telling me that the Layout inside the component as the same name and refuse to continue So I decide to simplify the problem by making a simple component like this: Create a new fresh bpl package Put on it a unit.pas On this unit, I create a class deriving from TRectangle with an edit and a button Add the code for the OnClick event to "ShowMessage" the edit content when i click on the button compile and install the package And the problem ? When I move this new fresh component from the palette on the form and play it the click event is not firing But if I put the unit of the bpl package inside a new FMX project and I launch it directly by code from the form 1 in the oncreate event that works ! I have Delphi 12 Athens on Windows 11 I do not understand why it is not working Here is the code of the unit inside the bpl : unit uniEssai2; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls, Fmx.Edit, FMX.Objects; type TFrame2 = class(TRectangle) Edit: TEdit; Button: TButton; procedure Test(Sender: TObject); private public constructor Create(AOwner: TComponent); override; destructor Destroy; override; end; procedure Register; implementation procedure Register; begin RegisterComponents('ZEssai', [TFrame2]); end; { TFrame2 } procedure TFrame2.Test(Sender: TObject); begin ShowMessage(Edit.Text); end; constructor TFrame2.Create(AOwner: TComponent); begin inherited Create(AOwner); Edit := TEdit.Create(Self); Edit.Parent := Self; Edit.Position.X := 8; Edit.Position.Y := 8; Edit.Width := 100; Button := TButton.Create(Self); Button.Parent := Self; Button.Text := 'Click'; Button.Position.X := 8; Button.Position.Y := 40; Button.Width := 60; Button.OnClick := Test; end; destructor TFrame2.Destroy; begin Button.Free; Edit.Free; inherited; end; end. Do you have an idea of what is wrong? The example is very basic I can't understand what is wrong? Thanks for your help. Share this post Link to post
DelphiUdIT 178 Posted November 7 I know that EVERY components of FMX project should have 'Name' property SET. And of course all must be differents. Share this post Link to post
DelphiTheWorld 0 Posted November 7 Hi, Thanks for the repy. I tried to add a name for edit and button but it doesn't works better unfortunately But if you create a frame and make right click add to palette without using the .bpl package solution, you can put three times the same frame on a form and it will work even if on the same form you have 3 objects of 3 differents frames with the same name. But if you choose the .bpl package solution it is no more working. But thanks again for your intervention. Share this post Link to post
Vincent Gsell 11 Posted November 7 You can put frame's name property at blank : No more "name" problem. The issue "3 times" is weird 🙂 Share this post Link to post
DelphiTheWorld 0 Posted November 7 Hi, Thanks for your help, Yes I tried and effectively the system is no more claiming for same name but in runtime is still doesn't take properties in consideration but it still work at design time. It is crazy. Is there someone with a Delphi 12 Athen version to reproduce the problem to see if ti is the same with another configuration ? Thansk again to all to help me. Share this post Link to post
Vincent Gsell 11 Posted November 7 Wow : I do not see that you use a "TRectangle" as base object : I Apologize because your "name" issue become evident !! your childs objects, depending of their types, could lead to problem -> Have you *any* reason to not use a "real" FMX TFrame instead ? I see you do that on a first attempt, are you sure that you have not doing something wrong ? TFrame class (The real one, not your Rectangle inherited !) is exacly matching what your are trying to do, and in this case, naming is managed, because TFrame is an "isolated" class, as TForm. Share this post Link to post
DelphiTheWorld 0 Posted November 7 Yes the last one that I have copied is like that but I have tested many combinations. First time I have tried with a real TFrame FMX (.pas + .fmx) but it doesn't work so I have decided to code a simpler case and I tried to make a component derived of TControl, TShape, Trectangle the last one. You have an edit and a button on a trectangle. When you move on the form you see visually the component correctly and when you run it you can write on the edit; click on the button but nothing appears. But in my code you see that I'm calling the showmessage with the content of the edit. Share this post Link to post
Patrick PREMARTIN 76 Posted November 7 Using a TFrame in the form editor don't manage its published properties. You have to register it as a real component for that. For the name, the simpler way to manage it is to add "Name := ''" in the TFrame constructor. The IDE will do the needed things to give one and if you create it by code you won't have the problem of duplicate names. The Click event should work but by doing like in your code you'll have a risk of duplicate components depending on how the users/developers use your component. Add published property as TNotifyEvent on the TFrame and put its value to your button in an override AfterConstruction method. It should work better. Don't forget to check ComponentState variable to do the good thing between IDE form editor and a real program. Share this post Link to post
Patrick PREMARTIN 76 Posted November 7 After some check on my repositories, here are two FMX components you could use as sample to adapt your code : - A TBitBtn like component with a TText and a TGlyph as a TControl descendant. I created a TFrame to show what I need and transformed the code to this to obtain my component. (search "Stored" and see ho I manage the click event for the TControl) https://github.com/DeveloppeurPascal/Pairpix/blob/main/src/uGameButton.pas - The non visual component for my About Box dialog which does some things in the IDE and others on a real project like changing the main form Caption. (search "ComponentState" in the source and see how I manage the component properties) https://github.com/DeveloppeurPascal/AboutDialog-Delphi-Component/blob/main/src/Olf.FMX.AboutDialog.pas Share this post Link to post
DelphiTheWorld 0 Posted November 7 Hi, Many thanks Patrick for your valuable answer. Quote Using a TFrame in the form editor don't manage its published properties. You have to register it as a real component for that. Of course it is what I've done in my first package bpl (not mentioned here) but as I have some problems with the real component (only in runtime) I have created a new one with a simple unit to reproduce a "School example" with edit and button. I read carrefully the precious link you gave me and I don't think to misuse the concepts (but perhaps I'm wrong 🙂). In my case, I don't think that "ComponentState" be very useful because the component can do the same thing in designtime or in runtime (but I was aware of that). Better than a long speech I share the source code of the simple example that it doesn't work on my Delphi. You can change the name of the pallet or whatever. Here my steps to reproduce my case: Start Delphi with admin rights (to avoid problems of the .bpl package in the public user, etc.) Open the "PaquetEssai.bpl" Build the package Install the package Open a second Delphi (normally, not with admin rights) Create a new blank FMX application Select in the pallet "Tframe2" (on my case but if you change the name take the good one) and move it in the form Run it Set a text manually inside the Edit Click on the button Surprise! In my case i have nothing but normally I should have a "ShowMessage" with the content of the Edit Tell me if you succeeds in your development environment please. Thanks a lot for your assistance, much appreciated. Essai.zip Share this post Link to post
DelphiTheWorld 0 Posted November 7 And if you have enough energy, here is the real package with the frames with their different published properties that I spoke initially. That the same steps of the previous post. You will see here that you are able to put the components on the form and to change the properties (Error, Open, Orientation, etc.) at design time but when you run the application, changing properties dynamically using a button for example has no effects on the components. TestD3.zip Share this post Link to post
Patrick PREMARTIN 76 Posted November 8 Hi I fixed the "essai" project. Here it is with a sample project. The Stored property must be used to avoid the copy of components in the DFM/FMX file. If you forgot it the program create local components in front of the objects created by the component. The click worked, but you couldn't click on the good button. To test if you do things good, use Alt+F12 in the form editor one or more times. If it adds components in the structure view, you missed the Stored and have to use it. You also need to (re)publish position&other properties on your Control descendant if you want to display it at the same position than in the IDE when you execute the program. I let you fixe your real component and tell us if its good or if you need more hep on it. 🙂 Essai-fixed.zip Share this post Link to post
Patrick PREMARTIN 76 Posted November 8 Just one more thing : if you use a container (Control, Layout or TFrame) as a component, don't forget to align the components you create in it or manage the Resize(d) event to fixed their size in the container. Share this post Link to post
DelphiTheWorld 0 Posted November 8 Hi the fourm, Fresh news today, it works! Thanks a lot for the assistance, I was very desperate. Now I feel so stupid to have been blocked for a so small thing like a property. I think now I will never forget "Stored" property . And thanks also for the explanation it is clearer for me. I tried the trick with Alt + F12 and effectively is multiplying the components for each call to Alt + F12 twice. Quote You also need to (re)publish position&other properties on your Control descendant if you want to display it at the same position than in the IDE when you execute the program. Yes of course but it was a stupid program to make a very small basic test so I wrote it in a minute. Quote Just one more thing : if you use a container (Control, Layout or TFrame) as a component, don't forget to align the components you create in it or manage the Resize(d) event to fixed their size in the container. Yes, I saw your webinar and if I remember well you put "Content" for the "Align" of the top Layout. I'm thanking you twice because for the TestD3.bpl package I used the technique you explain on the webinar with the frames. I find it quicker than making all dynamically as I was processing by the past in VCL with Delphi 2010. So now I will work on TestD3 to try to solve the remaining problems. Do you advise me to put the "Name := '';" for all the components inside the constructor of Tframe ? And to access the component like that (TLabel(Components[5]).Text := Value;) for example? I keep you informed and thanks again. Share this post Link to post
Patrick PREMARTIN 76 Posted November 8 Just for the others, the webinar is this one "create components without creating components" : (in French, with auto caption and auto translation available in YT player). 1 hour ago, DelphiTheWorld said: Do you advise me to put the "Name := '';" for all the components inside the constructor of Tframe ? And to access the component like that (TLabel(Components[5]).Text := Value;) for example? For the Name, yes. If you want to use more than ont "TFrame component" on your forms it's needed. And for the access to components, never use it : create public or published properties. The user of a component don't have to know its content. It can move, the components order can change, and with FMX if you deal with styles one day it's too dangerous. It's not a good plan for long-term maintenance. Share this post Link to post
DelphiTheWorld 0 Posted November 8 Yes but inside the properties how is it the alternative way to proceed to access the component? For example, I design quickly on the Frame visually a component (e.g. : move a TImage on the Frame named imgMyImage). In this case is no more a "variable" inside the class like for the Edit and the Button of the previous example. Following the advice, inside the Frame constructor I will do something like this imgMyImage.Name := ''; But after that inside the setter of my property I will probably not be able to do imgMyImage.Bitmap.LoadFromStream(ResourceStream); because the name is no more accessible not ? I think the only way is to look for the new name of the TImage (perhaps Components[5]) and to cast like that : TImage(Components[5]).Bitmap.LoadFromStream(ResourceStream);. At least I suppose. I will make some tests to check that. But perhaps I'm wrong like for the Stored ? But thanks again to enlight me. Share this post Link to post
Patrick PREMARTIN 76 Posted November 8 You don't need to set their Name. It's only necessary for the TFrame container. The Name property is only needed to link variables in the classes and the ressources in the DFM/FMX. When you create things by code the Name is not used. Inside the component store your objects instances in private or protected fields/variables instead of local variables in the methods. It won't depend on the possible auto generated names. Share this post Link to post
DelphiTheWorld 0 Posted November 12 Hi the forum, Thanks Patrick for your help and your answer. So finally, I have proceed like that : In the Frame constructor i remove all the objects names of the Frame I memorized the "ComponentIndex" of the object of the Frame I'm interested to interact When I need to use it, I'm casting by the class and use the good index! For example: TLabel(Components[IndexMemorized]).Text := 'MyText'; I'm joining you my final solution package. Again thanks a lot to everybody for your help. TestD3.zip Share this post Link to post