Reputation: 1
Suppose I have 1 main form. Main form contains two buttons (Open and Close), clicking on each button creates a frame with the Main form as the parent/owner. The frame contains 3 buttons (Add, Edit and Delete) with the sample code below:
Frame Code:
unit UntFrame;
...
type
TFmeMain = class(TFrame)
procedure AddClick(Sender: TObject);
procedure EditClick(Sender: TObject);
procedure DeleteClick(Sender: TObject);
private ...
public ...
end;
implementation
{$R *.dfm}
uses ...
procedure TFmeMain.AddClick(Sender: TObject);
begin
AddBtnClick;
end;
procedure TFmeMain.EditClick(Sender: TObject);
begin
EditBtnClick;
end;
procedure TFmeMain.DeleteClick(Sender: TObject);
begin
DelBtnClick;
end;
end.
The 3 methods (AddBtnClick, EditBtnClick and DelBtnClick) used by the frame exists on two different units namely UntOpen and UntClose but does things differently depending on the created frame. UntOpen should be used by the frame when the Open button is clicked, UntClose is for when the Close button is clicked from the main menu.
UntOpen Code:
unit UntOpen;
...
procedure AddBtnClick;
procedure EditBtnClick;
procedure DelBtnClick;
implementation
procedure AddBtnClick;
begin
ShowMessage('add open');
end;
procedure EditBtnClick;
begin
ShowMessage('edit open');
end;
procedure DelBtnClick;
begin
ShowMessage('delete open');
end;
end.
UntClose Code:
unit UntClose;
...
procedure AddBtnClick;
procedure EditBtnClick;
procedure DelBtnClick;
implementation
procedure AddBtnClick;
begin
ShowMessage('add close');
end;
procedure EditBtnClick;
begin
ShowMessage('edit close');
end;
procedure DelBtnClick;
begin
ShowMessage('delete close');
end;
end.
I want to add a unit dynamically (if possible) to the frames' uses clause each time that it is created so that clicking on the frame's add, edit or delete button fires up the correct method (method from the UntOpen if Open button is clicked or method from UntClose if Close button is clicked).
Or is there more efficient way of doing this?
Thanks.
Upvotes: 0
Views: 576
Reputation: 163317
You cannot use units dynamically; the uses clause cannot be manipulated at run time. You appear to want to change the unit list so that your frame's code, which already calls AddBtnClick
, will magically choose the function from one unit or the other.
Delphi doesn't work that way. If you really want something like that, try Python.
Delphi units are a compile-time construct. They cannot be manipulated at run time. At compile time, the compiler sees your call to AddBtnClick
, and it resolves — binds — the name then and there according to what units you've already used. You can't rebind the name later.
Instead, you can pass parameters to your frame class constructor. Put your button functions into data structures, and then pass those objects to the frame. (This is also known as dependency injection.) For example, you could start with this abstract class:
type
TButtonBehavior = class
class procedure AddBtnClick; virtual; abstract;
class procedure EditBtnClick; virtual; abstract;
class procedure DelBtnClick; virtual; abstract;
end;
Then, define your frame to receive a descendant of that class, and write your button handlers in terms of that value:
type
TButtonBehaviorClass = class of TButtonBehavior;
TMainFrame = class(TFrame)
private
FBehavior: TButtonBehaviorClass;
...
constructor TMainFrame.Create(AOwner: TComponent; ABehavior: TButtonBehaviorClass);
begin
inherited Create(AOwner);
FBehavior := ABehavior;
end;
procedure TMainFrame.AddBtnClick(Sender: TObject);
begin
FBehavior.AddBtnClick;
end;
Next, define descendants of the abstract class for each of the sets of behavior you want your frame to support. You can define them in separate units if you want, but since they're already in separate classes, further separation isn't required.
type
TOpenBehavior = class(TButtonBehavior)
class procedure AddBtnClick; override;
class procedure EditBtnClick; override;
class procedure DelBtnClick; override;
end;
TCloseBehavior = class(TButtonBehavior)
class procedure AddBtnClick; override;
class procedure EditBtnClick; override;
class procedure DelBtnClick; override;
end;
Finally, pass one of those classes to the frame constructor when you create a new instance of the frame.
Frame := TMainFrame.Create(Self, TOpenBehavior);
Upvotes: 5
Reputation: 1349
If I were you I would try this solution:
Main frame:
unit UntFrame;
...
uses
UntOpen, UntClose, ...;
type
TSelectedPage = (spOpen, spClose);
TFmeMain = class(TFrame)
procedure AddClick(Sender: TObject);
procedure EditClick(Sender: TObject);
procedure DeleteClick(Sender: TObject);
private
FSelectedPage: TSelectedPage;
...
public ...
end;
implementation
{$R *.dfm}
uses ...
procedure TFmeMain.AddClick(Sender: TObject);
begin
case FSelectedPage of:
spOpen: TUntOpen.AddBtnClick;
spClose: TUntClose.AddBtnClick;
end;
end;
procedure TFmeMain.EditClick(Sender: TObject);
begin
case FSelectedPage of:
spOpen: TUntOpen.EditBtnClick;
spClose: TUntClose.EditBtnClick;
end;
end;
procedure TFmeMain.DeleteClick(Sender: TObject);
begin
case FSelectedPage of:
spOpen: TUntOpen.DelBtnClick;
spClose: TUntClose.DelBtnClick;
end;
end;
end.
Open unit:
unit UntOpen;
...
type
TUntOpen = class
public
class procedure AddBtnClick;
class procedure EditBtnClick;
class procedure DelBtnClick;
end;
implementation
class procedure TUntOpen.AddBtnClick;
begin
ShowMessage('add open');
end;
class procedure TUntOpen.EditBtnClick;
begin
ShowMessage('edit open');
end;
class procedure TUntOpen.DelBtnClick;
begin
ShowMessage('delete open');
end;
end.
Close unit:
unit UntClose;
...
type
TUntClose = class
public
class procedure AddBtnClick;
class procedure EditBtnClick;
class procedure DelBtnClick;
end;
implementation
class procedure TUntClose.AddBtnClick;
begin
ShowMessage('add close');
end;
class procedure TUntClose.EditBtnClick;
begin
ShowMessage('edit close');
end;
class procedure TUntClose.DelBtnClick;
begin
ShowMessage('delete close');
end;
end.
This is the OOP way to do what you are trying to achieve, and it is possible in Delphi.
Upvotes: 0
Reputation: 597051
Try something more like this instead:
unit UntFrame;
...
type
TFmeMain = class(TFrame)
procedure AddClick(Sender: TObject);
procedure EditClick(Sender: TObject);
procedure DeleteClick(Sender: TObject);
public
OnAdd: procedure;
OnEdit: procedure;
OnDelete: procedure;
end;
implementation
{$R *.dfm}
procedure TFmeMain.AddClick(Sender: TObject);
begin
if Assigned(OnAdd) then OnAdd;
end;
procedure TFmeMain.EditClick(Sender: TObject);
begin
if Assigned(OnEdit) then OnEdit;
end;
procedure TFmeMain.DeleteClick(Sender: TObject);
begin
if Assigned(OnDelete) then OnDelete;
end;
end.
unit MainForm;
...
uses
..., UntFrame, UntOpen, UntClose;
...
procedure TFormMain.OpenClick(Sender: TObject);
begin
with TFmeMain.Create(Self) do
begin
Parent := ...;
OnAdd := Addr(UntOpen.AddBtnClick);
OnEdit := Addr(UntOpen.EditBtnClick);
OnDelete := Addr(UntOpen.DelBtnClick);
end;
end;
procedure TFormMain.CloseClick(Sender: TObject);
begin
with TFmeMain.Create(Self) do
begin
Parent := ...;
OnAdd := Addr(UntClose.AddBtnClick);
OnEdit := Addr(UntClose.EditBtnClick);
OnDelete := Addr(UntClose.DelBtnClick);
end;
end;
end.
Upvotes: 0