Stano 144 Posted January 23, 2021 (edited) I'm trying to create a class that returns different types of components. Specifically, it is a TMS TDBxxSource for TDBPlanner. All are descendants of TDBItems. Use for example in SpinEdit, which would serve all TDBxxSource. There is a separate SpinEdit for each TDBxxSource. I only want one OnClick event for them. The class must return, according to the index, the specific TDBxxSource. Not TDBItems, because I would have to cast it in OnClick. This is nonsense. The class would lose its meaning. Example of use procedure TfrmPlannerRole.advsedDayScaleChange(Sender: TObject); var SpinEdit: TAdvSpinEdit; begin SpinEdit := TAdvSpinEdit(Sender); MyClass.DBSource(5).VariousTypes := SpinEdit.Value; end; Originally at https://forum.delphi.cz/index.php/topic,17355.0.html There is silence. Edited January 23, 2021 by Stano Share this post Link to post
FPiette 387 Posted January 23, 2021 I don't understand your question! 8 minutes ago, Stano said: I'm trying to create a class that returns different types of components. A class do not "return different types of component". A class could have a method returning a value which can be an object type or an object instance or another data type. Please rephrase your question... Share this post Link to post
Stano 144 Posted January 23, 2021 2 minutes ago, FPiette said: A class do not "return different types of component". A class could have a method returning a value which can be an object type or an object instance or another data type. I'm aware of that. Even that it always has to be only one kind / type! That's why I used the term "components" to indicate what I really want. It should always be returned to a different type. Share this post Link to post
FPiette 387 Posted January 23, 2021 9 minutes ago, Stano said: That's why I used the term "components" to indicate what I really want. You may understand what you want, but at least I don't! If you want a good answer, you have to formulate a good question. If you want to use your own terms, you must describe each one using concept of Delphi/Object Pascal. And don't forget that not everybody is familiar with non standard component you are using. You'd better express your requirements using only what comes out of Delphi box. Share this post Link to post
Stano 144 Posted January 23, 2021 procedure TfrmPlannerRole.advsedDayScaleChange(Sender: TObject); var SpinEdit: TAdvSpinEdit; begin SpinEdit := TAdvSpinEdit(Sender); MyClass.DBSource(5).Top := SpinEdit.Value; // TPanel end; procedure TfrmPlannerRole.advsedDayScaleChange(Sender: TObject); var SpinEdit: TAdvSpinEdit; begin SpinEdit := TAdvSpinEdit(Sender); MyClass.DBSource(3).Value := SpinEdit.Value; // TSpinEdit end; Perhaps the examples will explain. Share this post Link to post
FPiette 387 Posted January 23, 2021 53 minutes ago, Stano said: Perhaps the examples will explain. Sorry, it doesn't explain anything. 54 minutes ago, Stano said: MyClass.DBSource(3).Value := SpinEdit.Value; // TSpinEdit MyClass.DBSource(5).Top := SpinEdit.Value; // TPanel What are those lines supposed to do? What is MyClass? What is method DBSource supposed to do? What is the argument? Share this post Link to post
Stano 144 Posted January 23, 2021 1 minute ago, FPiette said: What are those lines supposed to do? What is MyClass? What is method DBSource supposed to do? What is the argument? MyClass - is my class I want to create DBSource - some method with parameter (AIndex: Integer). According to the parameter returns for example TSpinEdit, TPanel ... Share this post Link to post
David Heffernan 2364 Posted January 23, 2021 A function's return type is defined at compile time. So whilst you might return objects of different types in the implementation, the type that you declare as the return value type is determined when ylthe code is compiled, and must be an ancestor of all possible types that are actually returned. This is strong typing in action. Types determined at compile time. That's how delphi is. Dynamic typing seems like what you are wanting here. But that isn't something that exists in Delphi. That's something that you find typically in lamguages like Python. Share this post Link to post
FPiette 387 Posted January 23, 2021 1 hour ago, Stano said: DBSource - some method with parameter (AIndex: Integer). According to the parameter returns for example TSpinEdit, TPanel You mean return an instance of TSpinEdit or TPanel, or do you mean it return a class type (In which case the rest of the line is wrong). So let's assume it returns an instance of a class like TSpinEdit or TPanel. This can be done by returning a common ancestor such as TComponent. But which instance is returned? But don't expect the compiler to generate code to access properties like Value or Top. It can only access properties declared in the base class. Using RTTI, it is possible to have more or less the equivalent: MyClass.DBSource(3, 'Value', SpinEdit, 'Value'); // TSpinEdit MyClass.DBSource(5, 'Top', SpinEdit, 'Value); // TPanel RTTI, under some conditions, will allow to discover a property of a given name, his type and setter/getter. I don't see any advantage doing such trick. Share this post Link to post
Stano 144 Posted January 23, 2021 (edited) Well thank you. I was hoping to do it with some trick. Edited January 23, 2021 by Stano Share this post Link to post
Guest Posted January 23, 2021 (edited) maybe using "polyphormism" to "DBSource, then, depending on the current class in use, the variable (polypformic) will have its value defined. Would be that? Marco Cantu github with sample of his books: https://github.com/MarcoDelphiBooks Edited January 23, 2021 by Guest Share this post Link to post
David Heffernan 2364 Posted January 23, 2021 (edited) 58 minutes ago, emailx45 said: maybe using "polyphormism" to "DBSource, then, depending on the current class in use, the variable (polypformic) will have its value defined. Would be that? No. The polymorphism applies to method dispatch, and not to the types. Edited January 23, 2021 by David Heffernan Share this post Link to post
Lars Fosdal 1800 Posted January 23, 2021 It can be done if the Controls have the same base class, but if you need to interact with the controls in a generic way, it would quickly become unmanageable without a lot of wrapper code, and even then it would probably be just as easy to simply return some enumerated value that decides the appropriate code paths later on. Share this post Link to post
Stano 144 Posted January 23, 2021 I have several events that are identical in content. I only use a different component there every time. In the example, I have dbmlmnsrMultiMonth. And I want to use this event for other components that do the same thing. Only with another dbxxx. . So now I have 10 x SpineditxxxChange. And I want a single SpineditxxxChange event! Every time I need to get the right dbxxx component there. Share this post Link to post
Lars Fosdal 1800 Posted January 23, 2021 Maybe it's a language barrier thing, but I am still having problems understanding the actual problem you are trying to solve. Share this post Link to post
Stéphane Wierzbicki 45 Posted January 23, 2021 1 hour ago, Stano said: I have several events that are identical in content. I only use a different component there every time. In the example, I have dbmlmnsrMultiMonth. And I want to use this event for other components that do the same thing. Only with another dbxxx. . So now I have 10 x SpineditxxxChange. And I want a single SpineditxxxChange event! Every time I need to get the right dbxxx component there. Why don't you just create one metWhySpineditxxxChange event and bind it to all your components change event? This can be done at design time as well as runtime. Share this post Link to post
Attila Kovacs 634 Posted January 23, 2021 (edited) Brrrr, the oldschool way is to use DB Aware controls, like TDBSpinEdit and set its datasource to point to the dataset you want. Then you can write: procedure OnClick(Sender: TObeject); begin if Sender is TDBSpinEdit then TDBSpinEdit(Sender).Datasource.Dataset.CheckBrowseMode; // for example end; But, depending on what you are trying to achieve in OnClick it's possible that you have to move that code into the dataset's or its fields' events. (If we are talking about VCL and I understand your issue correctly) Edited January 23, 2021 by Attila Kovacs Share this post Link to post
Guest Posted January 23, 2021 (edited) Another thing, if the "Events" have same signature (same params on calls) you can create a equal procedure and sign it in your "SpinEdit.OnChange" or any other events pertinent in fact, same params "TYPE" the param names can be others procedure TForm1.SpinEdit1Change(Sender: TObject); // signature of this event // then you can create on procedure on "Published" section with equal signature type TForm1 = class(TForm) SpinEdit1: TSpinEdit; SpinEdit2: TSpinEdit; SpinEdit3: TSpinEdit; SpinEdit4: TSpinEdit; DataSource1: TDataSource; DataSource2: TDataSource; DataSource3: TDataSource; DataSource4: TDataSource; procedure FormCreate(Sender: TObject); private // published procedure prcMySpinEditsChange(Sender: TObject); public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin SpinEdit1.Tag := 1; // to control the "case", but, "Tag" is not good for that, at all! SpinEdit2.Tag := 2; SpinEdit3.Tag := 3; SpinEdit4.Tag := 4; // SpinEdit1.OnChange := prcMySpinEditsChange; SpinEdit2.OnChange := prcMySpinEditsChange; SpinEdit3.OnChange := prcMySpinEditsChange; SpinEdit4.OnChange := prcMySpinEditsChange; end; procedure TForm1.prcMySpinEditsChange(Sender: TObject); var lFindCompIfExist: TComponent; begin // // you should have some way to verify the current values - then, your class should do it, or, in your code like this: // lFindCompIfExist := Self.FindComponent(Format('DataSource%d', [(Sender as TSpinEdit).Tag])); // if not(lFindCompIfExist = nil) and (lFindCompIfExist is TDataSource) then begin ShowMessage( { } Format('DataSource name = %s', [ { } lFindCompIfExist.Name { } ]) { } ); end; // else --- what I should do? end; hug Edited January 23, 2021 by Guest Share this post Link to post
Stano 144 Posted January 24, 2021 11 hours ago, Lars Fosdal said: Možno je to vec s jazykovou bariérou, ale stále mám problémy s porozumením skutočného problému, ktorý sa snažíte vyriešiť. Even those who know Slovak did not understand I already have a solution. The topic is closed to me. Thank you all for your willingness to help me. Share this post Link to post
Stano 144 Posted January 24, 2021 11 hours ago, Stéphane Wierzbicki said: Why don't you just create one metWhySpineditxxxChange event and bind it to all your components change event? This can be done at design time as well as runtime. I tried to do it. I had a problem that I always needed a different component. I solve it using case .. of. In a separate class. Share this post Link to post
Fr0sT.Brutal 901 Posted January 25, 2021 MyClass.DBSource<TPanel>(5).Top := SpinEdit.Value; Share this post Link to post