Calling a procedure in Delphi - delphi

I have a procedure with Sender: TObject paramater
procedure TForm1.FormCreate(Sender: TObject);
How can I call this procedure again?
This version does not work:
TForm1.FormCreate(Sender: TObject);
Thanks in advance.

I assume that you wish to call the procedure FormCreate of an instance of a TForm1.
You can do FormCreate(Self) or FormCreate(nil) (or you can pass any TObject instance as the parameter) if you are inside the TForm1 class. Otherwise, you have to write Form1.FormCreate(Self) or Form1.FormCreate(nil) or similarly, where Form1 is the appropriate instance of the TForm1.
At any rate, it is not particularly 'elegant' to call the FormCreate procedure at later times. Indeed, the name clearly suggests that the procedure is called when the form is created.
If a particular piece of logic of your FormCreate method is needed at other stages and you simply do not want to duplicate code, you should probably implement that piece in the form of a separate method (procedure or function) and call it in FormCreate as well as in other parts of your program, as necessary.
But then, you might be better off moving that part of your business logic from FormCreate at all. What we typically do in FormCreate is create/initialise objects that are later uninitialised/destroyed in FormDestroy (if needed). So, think carefully what you are doing in FormCreate, maybe there's a better, logically more appropriate place for some or all of the actions you've implemented in this method.

Related

Delphi DUnitX tests creation of form twice

I created a TestCase with DUnitX which automatically generated some code and I'm confused as to how I should structure the test case.
The (automatically generated) code looks like the following:
procedure TestTBtnMgmtForm.SetUp;
begin
FBtnMgmtForm := TBtnMgmtForm.Create;
end;
procedure TestTBtnMgmtForm.TearDown;
begin
FBtnMgmtForm.Free;
FBtnMgmtForm := nil;
end;
procedure TestTBtnMgmtForm.TestFormCreate;
var
Sender: TObject;
begin
// TODO: Setup method call parameters
FBtnMgmtForm.FormCreate(Sender);
// TODO: Validate method results
end;
However, TBtnMgmtForm.Create will automatically call .FormCreate. Is it good practice to separate these two somehow? What is the difference or should be the difference between .Create and .FormCreate?
The constructor of a form will call the OnCreate event handler, if it is assigned. In your case it is assigned, to the function named FormCreate.
As a general rule, event handlers are invoked by the framework and should not be called directly. I can't see enough of your code to be sure but my instincts tell me that you should not be calling FormCreate at all. It is the job of the framework to do that.
The point of OnCreate is that it allows you to inject code into the constructor of the form class without having to override the constructor. You can use the form designer to add the event handler and fill in the code. Personally I regard OnCreate as somewhat facile. Once you know how to override constructors it seems more explicit to do that.
You however appear to have a form with a parameterless constructor. That is odd. Usually you would override the virtual constructor declared in TComponent. I wonder why you are not doing that.

Delphi TForm constructor

I have already found something on stackoverflow but it doesn't really solve my doubt. I know that the correct way to create an object is, after the creation, surround the code in a try-finally block. But what about:
procedure TForm3.FormCreate(Sender: TObject);
begin
a := TClassX.Create;
end;
And then call:
procedure TForm3.FormDestroy(Sender: TObject);
begin
a.Free;
end;
Where a: TClassX; is a public declaration inside TForm3 class. Should I create the constructor and the destructor for the form, or I can use the code above? Is it safe?
The try/finally is there, or at least something equivalent. It just exists outside your code, higher up the call stack. Something like:
Form1 := TForm1.Create(nil);
try
// do stuff
finally
Form1.Free;
end;
Your OnCreate and OnDestroy handlers are called from the constructor and destructor, respectively, and so are protected.
So long as everybody plays by the rules nothing leaks. And the rules here are that objects created in the constructor and to be destroyed in the destructor. Whoever actually creates the object is responsible to ensure that it is destroyed no matter what. But that's the task of the consumer of your class rather than you.
I had some issues with this events some time ago so I would not recommend to use OnCreate/OnDestroy events in your application. Here are just some cases I remember:
VCL by default handles exception from OnCreate/OnDestroy events. Actually if a:=TClassX.Create; will generate an exception, it will be shown by application exception handler but the form will be created successfully keeping "a" variable equals to nil. This may lead to Access Violations if you try to access this variable later.
Depending on OldCreateOrder these events may be called either from constructor/destructor or from AfterConstruction/BeforeDestruction methods. It may also lead to Access Violations if you occasionally change OldCreateOrder in form descendants
And even more, it looks strange for me when you are using events instead of virtual functions. In most cases events are used to delegate the functionality to another objects (for example you assign a form's method to a button's OnClick event).

Delphi> Please explain this: type... procedure of object

I've encountered some code that's new to me...
I've never really seen a type declaration of a procedure of object, and I just don't
see the point.
Why couldn't the developer simply keep a field of type Boolean?
interface
type
TFinishedCaptureEvent = procedure(AFinished: Boolean) of object;
TFrameCard = class(TFrame)
...
private
FOnFinishedCapture: TFinishedCaptureEvent;
procedure DoUpdateMessage(AMessageType: TMessageType);
public
property OnFinishedCapture: TFinishedCaptureEvent read FOnFinishedCapture write FOnFinishedCapture;
end;
implementation
...
procedure TFrameCard.DoUpdateMessage(AMessageType: TMessageType);
begin
if Assigned(FOnFinishedCapture) then
FOnFinishedCapture(False);
...
end;
end.
Let's break this down into two parts to be easier to understand. First, procedure(AFinished: Boolean) isn't a boolean variable, it's a reference to a procedure that takes a boolean as a parameter. It's basically a procedure header, except without the procedure name because this is just a type definition. Any procedure that matches this signature can be assigned to this variable.
The of object part means that this isn't just a procedure reference, but a method reference; it has to belong to an object. The compiler needs to know the difference so that it can store the self pointer for the object together with the procedure pointer so it can be invoked properly, as the other posters have pointed out.
Basically, this is declaring a new event handler, and it's a pretty common pattern in Delphi. It's the same thing that the VCL does all over the place. When you create a button and assign an OnClick handler, it has to be a procedure (Sender: TObject) of object;. Your form gives the button a method reference referring to itself and the event handler procedure, and then the button uses that information to invoke the handler on the form when someone clicks it.
This code is doing the same thing. It's providing a way for some external object to be notified when DoUpdateMessage runs, using the standard Delphi idiom for event notification.
A procedure of object is a procedure reference for procedures contained in class instances. When calling procedures that are members of a class, the implict Self reference must be passed with the other parameters. Using procedure of object tells the compiler to store the Self reference with the procedure address inside the procedure reference, so that when the procedure is called via the procedure reference, the Self reference will be automatically passed.
In the code snippet you provided, TFinishedCaptureEvent is defined as a procedure of object, meaning that any variables created of its type will contain 2 values: the Self value and the procedure address. When this variable is assigned to, in particular when the assignment is inside a class, the compiler will automatically set the Self value inside this variable to the instance of the class that contains the procedure being assigned to the variable. When the variable is called (FOnFinishedCapture(False)), the compiler automatically passes the correct Self value back to the procedure that was assigned to this variable.
I don't understand how you relate this to a field of boolean.
But TFinishedCaptureEvent = procedure(AFinished: Boolean) of object declares a delegate/method pointer type, which is used for events. It's a record which contains a self pointer and a function pointer. When you call the delegate, the function is called with the self passed as a parameter to the function.

Communication between forms and frames

I've been working on a program in Delphi 2009. It very similar to the program "Mimics" by materialise, where you can create and manipulate 3D meshes. There are 4 panels with different aspects for viewing a 3D object (XY,YZ,XZ, and 3D perspective). Each of the panels is an instance of a custom frame I made for viewing 3D objects. The 4 panels are then loaded onto a form which has buttons and other components.
A problem that I am running into is that the frames must access subroutines of the form on which they reside. E.G. If I change something about the mesh im working on in one of the frames, ALL of the frames should be updated (refreshed) which is a procedure available in the parent form. But to call procedures on the parent form I have to include the parent form's unit file in the implementation uses clause of the 3D frame. That is fine, and this in general works without any trouble. The problem is that I cannot use the parent form to inherit from. If i create an inherited class from the parent form, the unit name and form name change and I must then alter the 3D frame to reference this new changed form.
Thats really the crux of my problem. I dont know how to reference the attributes of a parent form from its child frames without explicitly stating the name of the form. I want to be able to reuse and expand upon the parent form, but I dont see how its possible without also changing the 3D frames which are used by the form.
Any help would be greatly appreciated. Thank you.
So you have a self-contained component (a frame) that has to be able to invoke code from the form it's placed on, without having compile-time knowledge of the form itself? Sounds a lot like a TButton that doesn't know what to do with the form it's on when you click it, and the solution is the same: use an event handler. Add an OnChangeMesh (or something like that) event property to your frame, and have your form assign the appropriate method when it creates the frames.
Another option may be to define an interface that the parent form implements. It should have all the properties and methods that you want to access from your child frame, something like:
ImyFormInterface=interface
['{08BD9B3C-C48E-47B7-AE67-279277C7E024}']
function GetValue1: integer;
function GetValue2: integer;
procedure SetValue1(val: integer);
procedure SetValue2(val: integer);
procedure SomeMethod;
function GetSomeValue: integer;
property Value1: integer read GetValue1 write SetValue1;
property Value2: integer read GetValue2 write SetValue2;
end;
Then make your main form implement that interface:
TForm1 = class(TForm, ImyFormInterface)
private
{ Private declarations }
public
// Implement ImyFormInterface
function GetValue1: integer;
function GetValue2: integer;
procedure SetValue1(val: integer);
procedure SetValue2(val: integer);
procedure SomeMethod;
function GetSomeValue: integer;
public
{ Public declarations }
end;
Then in your frame you can use something like:
procedure Tframe1.Button1Click(Sender: TObject);
var pform: TcustomForm;
i: ImyFormInterface;
begin
pform:=GetParentForm(self);
if (pform.GetInterface(ImyFormInterface, i)) then
begin
i.SomeMethod;
i.Value1:=i.Value1+10;
Self.SomeProperty:=i.GetSomeValue;
end;
end;
Now if you inherit from your parent form it will all still work because you will still get the interface. Also, you could put your frames on an entirely new form and as long as that new form implements the interface then it will work there too.
You could use a subscription structure. Maintain a global list of the view-frames. If the frames need to update simply loop over this list and call the updae procedure for eacht of the frames. This allows you to have 1,2 or 100 frames update if something has changed.
If you want to go all OOP and be really happy about it: this is the observer pattern.
http://en.wikipedia.org/wiki/Observer_pattern
A final solution might be to check out visual form/frame inheritance.
It is possible to derive forms from a baseform and frames from a baseframe. Add virtual methods to the baseframe and override them in the inherited versions.

Using inherited in the "Create" constructor of an TObject

Rant: Should I call "inherited" in the constructor of a class derived from TObject or TPersistent?
constructor TMyObject.Create;
begin
inherited Create; // Delphi doc: Do not create instances of TPersistent. Use TPersistent as a base class when declaring objects that are not components, but that need to be saved to a stream or have their properties assigned to other objects.
VectorNames := TStringList.Create;
Clear;
end;
Yes. It does nothing, true, but it's harmless. I think there is value in being consistent about always calling the inherited constructor, without checking to see if there is, in fact, an implementation. Some will say that it's worth calling inherited Create because Embarcadero might add an implementation for TObject.Create in the future, but I doubt this is true; it would break existing code which does not call inherited Create. Still, I think it is a good idea to call it for the reason of consistency alone.
I always do this.
If you are refactoring and move code to a common ancestor, calling the inherited Create has the following advantages:
If the common ancestor has a constructor, you can't forget to call it.
If the common ancestor has a constructor with different parameters, the compiler warns you for this.
You can also override "procedure AfterConstruction". This procedure is always called, no matter what kind of constructor.
public
procedure AfterConstruction; override;
end;
procedure TfrmListBase.AfterConstruction;
begin
inherited;
//your stuff, always initialized, no matter what kind of constructor!
end;
For example: if you want to create an object with a different constructor than the normal TObject.Create, such as TComponent.Create(AOwner) or a custom (overloaded) constructor, you can get problems because your override is not called and (in this case) your "VectorNames" variable will be nil.
I call it, except when i need a very optimized constructor.

Resources