-
Content Count
116 -
Joined
-
Last visited
Everything posted by bravesofts
-
unit API.Generics; interface uses System.Classes // , System.Generics.Collections , System.Generics.Defaults ; type TSort = (sNone, sAsc, sDes); TDynamicObjectList<T: class> = class(TObjectList<T>) private fComparer: TComparison<T>; fSortField: string; fSort: TSort; function CompareNumbers(const L, R: Integer): Integer; function CompareObjects(const aLeft, aRight: T): Integer; public constructor CreateWithSort(const aSortField: string; aSort: TSort = sAsc); procedure Sort(aSort: TSort = sAsc); function IsSortedCorrectly: Boolean; end; implementation uses System.SysUtils , System.Rtti , System.TypInfo ; { TDynamicObjectList<T> } constructor TDynamicObjectList<T>.CreateWithSort(const aSortField: string; aSort: TSort); begin inherited Create(True); fSortField := aSortField; fSort := aSort; fComparer := CompareObjects; end; function TDynamicObjectList<T>.CompareNumbers(const L, R: Integer): Integer; begin Result := L - R; end; function TDynamicObjectList<T>.CompareObjects(const aLeft, aRight: T): Integer; var L_Ctx : TRttiContext; L_Typ : TRttiType; L_Prop : TRttiProperty; L_Left : TClass absolute aLeft; L_Right : TClass absolute aRight; L_LeftValue, L_RightValue: TValue; begin if fSortField = '' then begin // Use default comparer if no specific field is specified .. Result := TComparer<T>.Default.Compare(T(L_Left), T(L_Right)); Exit; end; L_Ctx := TRttiContext.Create; try L_Typ := L_Ctx.GetType(T); // Get RTTI for type ( T ) L_Prop := nil; L_Prop := L_Typ.GetProperty(fSortField); if Assigned(L_Prop) then begin L_LeftValue := L_Prop.GetValue(L_Left); L_RightValue := L_Prop.GetValue(L_Right); case L_LeftValue.Kind of tkInteger, tkInt64: case fSort of sAsc: Result := CompareNumbers(L_LeftValue.AsInteger, L_RightValue.AsInteger); sDes: Result := CompareNumbers(L_RightValue.AsInteger, L_LeftValue.AsInteger); else Result := TComparer<T>.Default.Compare(T(L_Left), T(L_Right)); end; tkString, tkWString, tkLString, tkUString: case fSort of sAsc: Result := CompareNumbers(Integer.Parse(L_LeftValue.AsString), Integer.Parse(L_RightValue.AsString)); sDes: Result := CompareNumbers(Integer.Parse(L_LeftValue.AsString), Integer.Parse(L_RightValue.AsString)); else Result := TComparer<T>.Default.Compare(T(L_Left), T(L_Right)); end; else TComparer<T>.Default.Compare(T(L_Left), T(L_Right)); end; end else Result := 0; // Handle case where property is not found finally L_Ctx.Free; end; end; function TDynamicObjectList<T>.IsSortedCorrectly: Boolean; var I: Integer; begin Result := True; for I := 1 to Count - 1 do begin if CompareObjects(Items[I - 1], Items[I]) > 0 then begin Result := False; Break; end; end; end; procedure TDynamicObjectList<T>.Sort(aSort: TSort); begin fSort := aSort; inherited Sort(TComparer<T>.Construct(fComparer)); end; end. using: in separate Unit: MyFonts.pas type TFonType = (ft_TTF, ft_OTF, ft_Unknown); TFontInfo = class strict private fFileID, fFontName : string; fFontType : TFonType; fFontFileName: string; private function Get_FontType: string; procedure Set_FontType(const aValue: string); public constructor Add(const aFileID, aFontName: string; const aFontType: TFonType); destructor Destroy; override; property ID: string read fFileID write fFileID; property FontName:string read fFontName write fFontName; property FontType:string read Get_FontType write Set_FontType; property FontFileName: string read fFontFileName write fFontFileName; end; TFontsList = class(TDynamicObjectList<TFontInfo>); in MainForm: uses MyFonts; procedure TMainView.FormCreate(Sender: TObject); var L_FontInfo: TFontInfo; L_ListItem: TListItem; begin fFontsRes_List := TFontsList.CreateWithSort('ID'); // Add some sample data fFontsLst.Add(TFontInfo.Add('3', 'Courier New', ft_TTF)); fFontsLst.Add(TFontInfo.Add('1', 'Arial', ft_TTF)); fFontsLst.Add(TFontInfo.Add('2', 'Times New Roman', ft_OTF)); // Sort the list by ID in Asc fFontsLst.Sort(sAsc); // Populate the ListView for L_FontInfo in fFontsLst do begin L_ListItem := LV_Fonts.Items.Add; L_ListItem.Caption := L_FontInfo.ID; L_ListItem.SubItems.Add(L_FontInfo.FontName); L_ListItem.SubItems.Add(L_FontInfo.FontType); L_ListItem.SubItems.Add(L_FontInfo.FontFileName); end; end; procedure TMainView.FormDestroy(Sender: TObject); begin fFontsRes_List.Free; end; currentlly it's works only with fields marked as string or integer but real value are in integer and sorted using : CompareNumbers
-
the Real Purpose of using Reintroduce
bravesofts replied to bravesofts's topic in Algorithms, Data Structures and Class Design
ok , I totally agree with that definition in dokwiki.. but here: https://stackoverflow.com/questions/53806/reintroducing-functions-in-delphi plese someone tell me Why all this confusion in link above, about something that was created specifically just for that senarion in dokwiki? atleast everyone there has a logic reason for that.. Please, I need to turn this page permanently... Jim McKeeth said: If you declare a method in a descendant class that has the same name as a method in an ancestor class then you are hiding that ancestor method — meaning if you have an instance of that descendant class (that is referenced as that class) then you will not get the behavior of the ancestor. When the ancestor's method is virtual or dynamic, the compiler will give you a warning. Now you have one of two choices to suppress that warning message: Adding the keyword reintroduce just tells the compiler you know you are hiding that method and it suppresses the warning. You can still use the inherited keyword within your implementation of that descended method to call the ancestor method. If the ancestor's method was virtual or dynamic then you can use override. It has the added behavior that if this descendant object is accessed through an expression of the ancestor type, then the call to that method will still be to the descendant method (which then may optionally call the ancestor through inherited). So difference between override and reintroduce is in polymorphism. With reintroduce, if you cast the descendant object as the parent type, then call that method you will get the ancestor method, but if you access it the descendant type then you will get the behavior of the descendant. With override you always get the descendant. If the ancestor method was neither virtual nor dynamic, then reintroduce does not apply because that behavior is implicit. (Actually you could use a class helper, but we won't go there now.) In spite of what Malach said, you can still call inherited in a reintroduced method, even if the parent was neither virtual nor dynamic. Essentially reintroduce is just like override, but it works with non-dynamic and non-virtual methods, and it does not replace the behavior if the object instance is accessed via an expression of the ancestor type. Further Explanation: Reintroduce is a way of communicating intent to the compiler that you did not make an error. We override a method in an ancestor with the override keyword, but it requires that the ancestor method be virtual or dynamic, and that you want the behavior to change when the object is accessed as the ancestor class. Now enter reintroduce. It lets you tell the compiler that you did not accidentally create a method with the same name as a virtual or dynamic ancestor method (which would be annoying if the compiler didn't warn you about). is there a deep example where introducing each case with strong reason individually ? It’s essential for my overall well-being to close this chapter once and for all... -
I'm confused...why didn't the Embarcadero take this seriously? Why does every Delphi developer have to install more than one version of Delphi to be able to support almost Android phones? On the other hand we find Android Studio, for example, with only one version of that IDE that still covers all Android phones, starting from android 5 up to the current latest version.!! is there a workaround solution that help to make Delphi 12 support even old Android phones? i mean (a real support not fake..) is there a complete SDK solution where users under delphi12 could support old phones starting from Android 5 to the latest current version ? thank you All
-
making Delphi 12 support even old Android phones?
bravesofts replied to bravesofts's topic in Delphi IDE and APIs
wow thank you @Dave Nottage that solution from [Delphi World] is working as a charm ! -
delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices?
bravesofts posted a topic in Cross-platform
i have this code here: fTask: ITask; fTask := TTask.Create( procedure begin while not True do Application.ProcessMessages; TThread.Synchronize(TThread.Current, procedure begin // update ui end); end); fTask.ExecuteWork; // this will stop here.. until [fTask] finish work !! In android didn't wait untill Task Complete !!- 24 replies
-
- android
- multithreading
-
(and 2 more)
Tagged with:
-
delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices?
bravesofts replied to bravesofts's topic in Cross-platform
sorry @Remy Lebeau no i didn't at that way !! --- i ask both question at the same time !! --- and with Your big and huge respect of your knowledge, I'm done learning that Method: [ITask.ExecuteWork] from ITask is: runs the task in the calling thread ... ---- again please: Forgive my ignorance and stupidity !! i was just there to ask and not because this site or other didn't help !! --- finally . i thank you all for your replys and especially for taking from your time.. i love you all & respect you all .. @Dalija Prasnikar regardless of others... i respect you a lot .- 24 replies
-
- android
- multithreading
-
(and 2 more)
Tagged with:
-
delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices?
bravesofts replied to bravesofts's topic in Cross-platform
also i learn that the Method ExecuteWork: [ is used to run the task in the calling thread => in my case the main App thread ] like inject or run a safe thread inside the MainThreadAPP and this exactly what i looking for.... --- so my question here: Why Method ExecuteWork Fail in mobile device (especially ANDROID) ? ----- is this have problem with Android OS ?? ----- Please don't tell me that Method : ExecuteWork is not a regular or illegal or what ever else ... otherwhise why the EMB Group add it inside the interface ITASK ? ---- what i know in language programming : the interface is safer and destinated at-least to users like me .... --- with best Respects & Regards ...- 24 replies
-
- android
- multithreading
-
(and 2 more)
Tagged with:
-
delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices?
bravesofts replied to bravesofts's topic in Cross-platform
sorry again ... --- last question: is it impossible to create threads in mobile devices while avoiding the main app thread from going to the next line of code until tasks complete ? for example this code here didn't work in android devices: begin _Taskcomplete := false; try fTask := TTask.Create( procedure begin // Here you do your task code while not _Taskcomplete do Lbl_Task.Text := ElapsedSec.ToString; TThread.Synchronize(nil, procedure begin // Here you can call code that needs to run after task is finished Lbl_Task.Text := 'task complete ..'; end); end); fTask.Start; finally while not _Taskcomplete do Application.ProcessMessage; // in Android the APP freeze !! showMessage('we wait until Task Complete to show you this message !!'); end; end; from what i learn above is i can only use wait function to run the SoCalled "After Task Complete Procedures or functions" inside the task thread using synchronize method..!!- 24 replies
-
- android
- multithreading
-
(and 2 more)
Tagged with:
-
delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices?
bravesofts replied to bravesofts's topic in Cross-platform
Not block the main thread in that definition... !!! I think the stupid sleep function is the unsafe way to block main thread... ---- I mean block main thread using the safe way like executeWork does... ---- I'm afread again : Delphi does not support background threads in Android and iOS devices where the main thread wait smoothly and safe...- 24 replies
-
- android
- multithreading
-
(and 2 more)
Tagged with:
-
delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices?
bravesofts replied to bravesofts's topic in Cross-platform
Is there a safe solution to block the main thread smoothly without freezing the app while waiting our task to complete "using the right task way above.. " Especially in mobile devices- 24 replies
-
- android
- multithreading
-
(and 2 more)
Tagged with:
-
delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices?
bravesofts replied to bravesofts's topic in Cross-platform
About my repository didn't help you understand my request... --- I simply if I Don't use itask.ExecuteWork; and use the regular Start; The main thread App will not wait for task completion and execute the next line code... But with executeWork I succeeded to force main thread App to wait smoothly without freezing the app.... I don't like use sleep function inside while loop in order to execute background thread... --- Try to use my wrong code (like I said before it's not complete...) in VCL and FMX windows example and you will find the magic of executeWork method.. --- NB: sorry for my wrong solution in my GIthub..- 24 replies
-
- android
- multithreading
-
(and 2 more)
Tagged with:
-
delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices?
bravesofts replied to bravesofts's topic in Cross-platform
In android maybe android service could help... Or add some Java activities that play our background threads safely while our main thread App is using while loop application.processmessage;- 24 replies
-
- android
- multithreading
-
(and 2 more)
Tagged with:
-
delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices?
bravesofts replied to bravesofts's topic in Cross-platform
Unfortunately didn't help at all... I see that post before..- 24 replies
-
- android
- multithreading
-
(and 2 more)
Tagged with:
-
delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices?
bravesofts replied to bravesofts's topic in Cross-platform
Is there any solution targeting the mobile devices!! ---- I'm afraid that : Delphi does not support background threads in Android and iOS devices !! ---- And if yes... I think it's OS problem or Firemonkey single Main Activity doesn't accept more activities !!!- 24 replies
-
- android
- multithreading
-
(and 2 more)
Tagged with:
-
delphi Thread ITask.ExecuteWork not wait until Task finish in mobile devices?
bravesofts replied to bravesofts's topic in Cross-platform
This is my git repository uses that method executeWork: Wait Solution Here Maybe help to understand my request.. Nb: my repo not complete yet... Wait Solution (VCL/FMX) Stop the Use of Stupid Sleep function !! Now with this Solution : your Main thread Should Wait until your wait function finsh her work without freezing the entire App using the stupid Sleep function !!! other Threads that are runing outside your MainThread (they still could work without Any Problem!!) using the method ExecuteWork from ITask we can force the App to wait until Our WaitThread finish work- 24 replies
-
- android
- multithreading
-
(and 2 more)
Tagged with:
-
Class Instance vs Object Instance
bravesofts posted a topic in Algorithms, Data Structures and Class Design
First : i have this code: type TClass_Instance = class(TClass_Ancestor) end; what happen at runtime when our program is using this Unit? i mean exactly this Explicit : TClass_Instance = class(TClass_Ancestor) does this Allocate something in Memory ? or system resources .... second: ihave this declaration here: var vObj_Instance: TClass_Instance; begin end; what happen at runtime when we are declaring some Objects ? i mean exactly this Declaration : vObj_Instance: TClass_Instance; does this Allocate something in Memory ? or system resources .... third: i have this code here: type {$M+} TBaseForm = class(TForm) // This my template Base Form procedure Abstracted_Event(Sender: TObject); virtual; abstract; end; TSubBase_1 = class(TBaseForm) // SubBase_1 Members goes here .. published procedure Abstracted_Event(Sender: TObject); Override; end; TSubBase_2 = class(TBaseForm) // SubBase_2 Members goes here .. published procedure Abstracted_Event(Sender: TObject); Override; end; TSubBase_3 = class(TBaseForm) // SubBase_3 Members goes here .. published procedure Abstracted_Event(Sender: TObject); Override; end; i have this super procedure for calling sub forms acording to their Class Names: procedure Get_SubForm(AFormClass: TFormClass; aOwner: TComponent; aParent: TWinControl); var vObjInstance: TBaseForm; // Define Object Instance Type; vRef: TBaseForm; // our Object vRef is the Universal variable for All SubForms that inherited from TBaseForm begin vObjInstance := TBaseForm(AFormClass.NewInstance); //Fill Object [vObjInstance] with [AFormClass.NewInstance] .. vRef := vObjInstance.Create(aOwner); //Fill Object [vRef] with [vObjInstance.Create] .. try vRef.Parent := aParent; vRef.Align := alClient; vRef.BorderStyle := bsNone; vRef.OnShow := vRef.Abstracted_Event; finally vRef.Show; end; end; my question is : what happen here: vObjInstance := TBaseForm(AFormClass.NewInstance); //Fill Object [vObjInstance] with [AFormClass.NewInstance] .. at runtime ...? does this line Above is trying to replace the first declaration Above here: var vObjInstance: TBaseForm; // Define Object Instance Type; in other words: does NewInstance Above is trying to redeclare our variable vObjInstance with Another Type ? if not (so what happen exactlly ?) Another sample Example: procedure TFrmMain.Btn_CreateObjClick(Sender: TObject); var vObj_Instance: TButton; // declaration Type of our Object vRef: TButton; begin vObj_Instance := TButton(TButton.NewInstance); vRef := vObj_Instance.Create(Self); try vRef.Parent := Self; vRef.Name := 'Btn_vObj'+ ComponentCount.ToString; vRef.SetBounds(Round(8 * fScaleFactor), Round(48 * fScaleFactor), Round(185 * fScaleFactor), Round(41 * fScaleFactor)); finally vRef.Visible := True; end; end; here i'm using the same approach Above that using TBaseForm but with one base Class TButton my question is: we used to use this Rule here: <vObject> := <ClassName>.<ConstructorName> ; but here we have an object trying to Allocate the memory (fiil the Class inside that variable) for Another Object ... my Remark: procedure TFrmMain.Btn_CreateObjClick(Sender: TObject); var // vObj_Instance: TButton; vRef: TButton; begin // vObj_Instance := TButton(TButton.NewInstance); vRef := Btn_CreateObj.Create(Self); try vRef.Parent := Self; vRef.Name := 'Btn_vObj'+ ComponentCount.ToString; vRef.SetBounds(Round(8 * fScaleFactor), Round(48 * fScaleFactor), Round(185 * fScaleFactor), Round(41 * fScaleFactor)); finally vRef.Visible := True; end; end; if we click on button Btn_CreateObj the object will be created but the Button Btn_CreateObj will be disappear !!! and when closing the app will have a memory leaks !!! my Approach of using another variable as a mediator, remind me with A & B replacement values var A, B, C: integer; begin A := 10; B := 5; // Solving requiring us Another Variable with the same Type C := A; A := B; B := C; // AND IT'S DONE .. end; finally: what is a Class Instance and an Object Instance? and is my Approach for creating base forms is a good approach or not ? thanks in Advance... -
Class Instance vs Object Instance
bravesofts replied to bravesofts's topic in Algorithms, Data Structures and Class Design
honestly i'm a native Delphi !!! ------- my post here is to understand exactly what delphi is that i was used before without a deep attention to delphi details -
Class Instance vs Object Instance
bravesofts replied to bravesofts's topic in Algorithms, Data Structures and Class Design
and what about the exe it's self ? does A variable having a type equal to a class is actually a pointer to the memory allocated for the class instance inside the exe it's self and not comming from calling the constructor. !!! i mean the delphi is deployed for us a ready to use objects variables that pointer to the exe it's self (pre Allocated Classes) -
Getting an Object Instance Name when ancestor is of TComponent
bravesofts posted a topic in Algorithms, Data Structures and Class Design
i have this Abstract Base Unit : unit UBase; interface uses System.Classes; type TBaseAbstract = class(TComponent) procedure Method(aObjectEvent: TNotifyEvent); virtual; abstract; end; TConcrete = class(TBaseAbstract) procedure Method(aObjectEvent: TNotifyEvent); override; strict private fReadOnlyProperty: string; public constructor New(aValue: string; aOwner: TComponent); destructor Destroy; override; property ReadOnlyProperty: string Read fReadOnlyProperty; // Read Only Property .. end; implementation { TConcrete } destructor TConcrete.Destroy; begin inherited; end; procedure TConcrete.Method(aObjectEvent: TNotifyEvent); begin aObjectEvent(Self) end; constructor TConcrete.New(aValue: string; aOwner: TComponent); begin inherited Create(aOwner); fReadOnlyProperty := aValue + Self.ClassName +' ] '+ sLineBreak + 'Object Instance Name is: [' + Self.Name +' ]'; end; end. in my App Demo Main Form i have this: var FrmMain: TFrmMain; implementation uses UBase; var fConcrete: TConcrete; fBASE: TBaseAbstract; {$R *.dfm} procedure TFrmMain.FormCreate(Sender: TObject); begin fConcrete := TConcrete.New('i''m a Read Only PROPERTY of [ ', Self); end; procedure TFrmMain.FormDestroy(Sender: TObject); begin fConcrete.Free; end; procedure TFrmMain.Btn_Normal_EventClick(Sender: TObject); begin ShowMessage('i''m an Event of [ ' + Sender.ClassName +' ] '+ sLineBreak + ' And My Object Instance Name IS: [ ' + TComponent(Sender).Name +' ]'); end; procedure TFrmMain.Btn_Call_MethodClick(Sender: TObject); begin fBASE := TConcrete.Create(nil); try fBASE.Method(Btn_Normal_Event.OnClick); finally fBASE.Free; end; end; procedure TFrmMain.Btn_Call_Abstract_MethodClick(Sender: TObject); begin fConcrete.Method(Btn_Normal_Event.OnClick); end; procedure TFrmMain.Btn_Get_Concret_PropertyClick(Sender: TObject); begin ShowMessage(fConcrete.ReadOnlyProperty); end; end. Btn_Normal_EventClick work correctlly (i got the name of this button when i click on it [Btn_Normal_Event]) but from fConcrete or fBase whether using Abstract Method or GetProperty the NAME IS EMPTY !!! ------------ do i missing something ? -
Getting an Object Instance Name when ancestor is of TComponent
bravesofts replied to bravesofts's topic in Algorithms, Data Structures and Class Design
a Nice Blog from Marco here -
Getting an Object Instance Name when ancestor is of TComponent
bravesofts replied to bravesofts's topic in Algorithms, Data Structures and Class Design
wow it seems a complicated backstage that the developer like me didn't know or even think about it previously !!! ------- i need to a respect time to understand exactly what happen inside that designtime backstage !!! thank you All for this Very valuable information ... -
Getting an Object Instance Name when ancestor is of TComponent
bravesofts replied to bravesofts's topic in Algorithms, Data Structures and Class Design
i have another Kinda strange question: (Maybe a Stupid hhh :) ) why the components that we create at designtime can call them using their NAME's Rather Call them from their Variables Names that Contains them ? in runtime we can do this for ex: procedure CreateButton(aParent: TWinControl; aBtnEvent: TNotifyEvent); var vButton: TButton; begin vButton := TButton.Create(Self); try vButton.Parent := aParent; vButton.Name := 'Btn_Test'; vButton.SetBounds(10, 10, 100, 25); vButton.Caption := 'Test'; vButton.OnClick := aBtnEvent; finally vButton.Visible := True; end; end; whereas any Object created at designtime we call them using their Name !!! -------- what is the secret thing or the missing part that should i know (seriously) to understand the difference between an Object Name at DesignTime & Obj Name RunTime ? -------- i know Logically that we can't Call any Obj not yet created in designtime from his NAME because it is not reconized for our Project yet (Therefore, we used variables instead), whereas we can call Objects that was created at designTime just from their Names because our Project know them & Recognize them !!(so how did recognize them and use TComponentName which is a string by default as pointer or i don't know as whatever is !!!) ------- what i mean exactlly: what happen to any OBJ CREATED AT DESIGNTIME makes delphi & our project call them from thier Names instead of variables Names like the RunTime Scenario does ?? -------- i know that my question is trivial & stupid !!! but (seriously) i'm lost here (i know that i missing An essential thing that childrens know ....) plz clarify to me the Secret behind delphi backstage designtime objects !!! Notice: All Objects will at the end created Atruntime (so why designtime is a superbox than others !!! (is a designtime = a temporary or pre runtime section or what is the word that can describe this superbox better than designtime ???) ) -------- in another meaning: why TComponentName of any OBJECT from ObjectInspector IS totally different from TComponentName of Runtime of any Object !!! they are both a string (TComponentName = type string;) from System.Classes -------- thanks in advance -
Getting an Object Instance Name when ancestor is of TComponent
bravesofts replied to bravesofts's topic in Algorithms, Data Structures and Class Design
thank you All for All this Infos ... ----- Really i'm not just low on caffeine :) i Missing one of the Pillar of delphi language hhh -
Getting an Object Instance Name when ancestor is of TComponent
bravesofts replied to bravesofts's topic in Algorithms, Data Structures and Class Design
is it fBase the name of that Object fBase ? and fConcrete the name of fConcrete Object -------- for example the NORMAL Button when user click on it it will give him the TButton as ClassName and the Btn_Normal_Event as Object Name where the Default was Button1 in Delphi -
Getting an Object Instance Name when ancestor is of TComponent
bravesofts replied to bravesofts's topic in Algorithms, Data Structures and Class Design
i test also the code for a Normal Class with ancestor TComponent the same Result !!! ------ why ?