Jump to content
Stano

A class that returns different types of components

Recommended Posts

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 by Stano

Share this post


Link to post

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
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
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
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
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
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

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
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

Well thank you. I was hoping to do it with some trick.

Edited by Stano

Share this post


Link to post

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 by emailx45

Share this post


Link to post
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 by David Heffernan

Share this post


Link to post

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

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

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
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

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 by Attila Kovacs

Share this post


Link to post

 

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 by emailx45

Share this post


Link to post
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:classic_biggrin:

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
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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×