|
Kanade's Delphi Stuff
Delphi Tips, Sample code and Tools
Copyright ©
1997-2004, Sanjay Kanade
| |
|
|
|
Delphi Tips: Concepts and Insight
|
Tip 19:
The magic of method pointers
(modified: 11 Nov 1999)
Tip 25:
Adding additional data members to forms
(modified: 20 Nov 1999)
Tip 21:
Application template approach
(modified: 02 Jan 2001)
Tip 20:
Interfaces
(modified: 13 Jan 2001)
|
|
|
|
19: The magic of method pointers
|
Date added/modified: 11 Nov 1999
You may not realize it but this is a concept at the core of Delphi technology and makes it truly amazing. You use it all the time without knowing about it. It might be interesting to see what this is all about.
I'll try to explain. Suppose you define a symbol TMyEvent with the following syntax:
type
TMyEvent = 'a function or procedure prototype' of object;
Where, you substitute a desired function prototype in the above statement.
Now, if you declare a variable of the type TMyEvent, it's actually a method pointer. At runtime, it can point to any method of any object as long as its function or procedure prototype exactly matches what you defined above. What does this mean? At run time, some work of an object can be done by a method of another object. This is great! Here is how Delphi uses method pointers all the time to ease your work.
Look at the definition of TNotifyEvent in Delphi's help. It's declared as a method pointer:
type TNotifyEvent = procedure(Sender: TObject) of object;
Now see how the property OnClick is defined for the class TControl:
property OnClick: TNotifyEvent;
Internally, FOnClick is a variable of type TNotifyEvent in TControl. So, it's actually a method pointer. When you double-click on the OnClick event of a TButton in the Object Inspector, here is what Delphi does for you:
- Delphi creates a procedure of the TNotifyEvent type as a method of the form. For example:
procedure MyForm.Button1Click(Sender: TObject);
begin
end;
- Then, it assigns this method to the OnClick property of that button which is internally assigned to the FOnClick method pointer.
- Now, if a click event occurs for the button, its TControl logic simply checks to see if FOnClick has been assigned a value (a method). If it does, it passes control to it.
If you think about it, the click event of the button is actually passed on to a method of the form. You can even change it at run time by assigning the property to any other method of any object as long as the prototype is same.
Once you understand this, you can do some very neat things which the environment doesn't provide for you. For example, visually, there is no way to combine one or more components to form a composite component. In other words, a Form can't become a visual component. But, if you do in code what Delphi does in Object Inspector, you can do it. You can put all those components inside a Panel, then dynamically assign events to the panel's methods. Yes, it's possible but you need to do everything in code.
I have tried this approach to create a RichEdit control which carries its toolbar and ruler along with it.
|
|
|
|
25: Adding additional data members to forms
|
Date added/modified: 20 Nov 1999
Suppose you want to add a new data member to a form. You want to initialize it in the constructor. What you will add is a constructor with your own name and the extra parameter:
constructor TMyForm.createIt(AOwner: TComponent; someState: boolean);
begin
inherited create(AOwner);
fSomeState := someState;
end;
That is OK. But, what if you want to use the initialized value of fSomeState in FormCreate method? Since create calls FormCreate, what you will get is the uninitialized value. So, for such a requirement, the proper way to do it would be:
constructor TMyForm.createIt(AOwner: TComponent; someState: boolean);
begin
fSomeState := someState;
inherited create(AOwner);
end;
Initially, when I posted some sample code on a newsgroup, someone claimed that this code is wrong, "As the create has not been called, the memory for the object instance is still not created." I was confused. But, then I discovered that what create does is only initialize the allocated memory. So, you can't use any code that references the base class variables before calling create. But, there is no harm if you initialize your own variables for this class. In fact, that is the only way to make sure that FormCreate gets them. Any objections?
|
|
|
|
21: Application template approach
|
Date added/modified: 02 Jan 2001
You must have seen lots and lots of components in Delphi. But, there are many programming chores other than using components. Consider the tasks which you need to repeat when writing new applications--new About box, new registry code, new window state remembering code, etc. Have you ever thought of making a generic application template where you just define constants in a file and compile it to get a new application which performs many of the housekeeping chores like displaying the about box? Such stuff needs a little effort but the results are dramatic.
To demonstrate this and many other solutions, I have created a complete sample application template in another product, Kanade's Appmodels. For more details, please see the sample code section of this web site.
|
|
|
|
20: Interfaces
|
Date added/modified: 13 Jan 2001
Another ace in Delphi's pack is the interface feature added to Object Pascal. I was thrilled to read about it in "Mastering Delphi 3" by Marco Cantu. If you skipped it, thinking that it is only meant for use with OLE, you missed a great feature! It will require some effort to understand the interfaces properly but it is worth it.
I find interfaces more useful even in my normal object oriented designs. Now, whenever I need to design complex objects where the object ownership moves around or where multiple inheritance is needed, I definitely consider the use of interfaces. If you design your system such that only interfaces are passed around and used everywhere, you don't have to worry about the object ownership and deletion. It will automatically get deleted when no one is using it.
I am so impressed with interfaces that I have used them to create my own object database system where an object when retrieved stays in memory till it is no longer in use. It is already working in one of my products. This system will form the backbone of many of my new programs. It uses interfaces along with the Delphi streaming system to implement the database objects which are smart. Moreover, implementing new objects becomes extremely simple as an automatic multiple inheritance is possible with interfaces.
Update: I have now completed by object database, and I am using it successfully in WhizFolders Organizer Pro in the new .wzfolder format files. However, I have not had time to make this database into a generic product for other developers. Perhaps, some day...
|
|
|
|
Copyright 1995-2004, Sanjay Kanade. All rights reserved. All trademarks and copyrights belong to their respective owners.
|
|
|
|