Delphi is based on OOP concepts, and in particular on the definition of new class types. The use of OOP is partially enforced by the visual development environment, because for every new form defined at design time, Delphi automatically defines a new class. In addition, every component visually placed on a form is an object of a class type available in or added to the system library.
As in most other modern OOP languages (including Java and C#), in Delphi a class-type variable doesn't provide the storage for the object, but is only a pointer or reference to the object in memory. Before you use the object, you must allocate memory for it by creating a new instance or by assigning an existing instance to the variable:
var Obj1, Obj2: TMyClass; begin // assign a newly created object Obj1 := TMyClass.Create; // assign to an existing object Obj2 := ExistingObject;
The call to Create invokes a default constructor available for every class, unless the class redefines it (as described later). To declare a new class data type in Delphi, with some local data fields and some methods, use the following syntax:
type TDate = class Month, Day, Year: Integer; procedure SetValue (m, d, y: Integer); function LeapYear: Boolean; end;
A method is defined with the function or procedure keyword, depending on whether it has a return value. Inside the class definition, methods can only be declared; they must be then defined in the implementation portion of the same unit. In this case, you prefix each method name with the name of the class it belongs to, using dot notation:
procedure TDate.SetValue (m, d, y: Integer); begin Month := m; Day := d; Year := y; end; function TDate.LeapYear: Boolean; begin // call IsLeapYear in SysUtils.pas Result := IsLeapYear (Year); end;
This is how you can use an object of the previously defined class:
var ADay: TDate; begin // create an object ADay := TDate.Create; try // use the object ADay.SetValue (1, 1, 2000); if ADay.LeapYear then ShowMessage ('Leap year: ' + IntToStr (ADay.Year)); finally // destroy the object ADay.Free; end; end;
Notice that ADay.LeapYear is an expression similar to ADay.Year, although the first is a function call and the second a direct data access. You can optionally add parentheses after the call of a function with no parameters. You can find the previous code snippets in the source code of the Dates1 example; the only difference is that the program creates a date based on the year provided in an edit box.
There is a lot more to say about methods. Here are some short notes about the features available in Delphi:
To emphasize the fact that Delphi components aren't much different from other objects (and also to demonstrate the use of the Self keyword), I've written the CreateComps example. This program has a form with no components and a handler for its OnMouseDown event, which I've chosen because it receives as a parameter the position of the mouse click (unlike the OnClick event). I need this information to create a button component in that position. Here is the method's code:
procedure TForm1.FormMouseDown (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var Btn: TButton; begin Btn := TButton.Create (Self); Btn.Parent := Self; Btn.Left := X; Btn.Top := Y; Btn.Width := Btn.Width + 50; Btn.Caption := Format ('Button at %d, %d', [X, Y]); end;
The effect of this code is to create buttons at mouse-click positions, as you can see in Figure 2.1. In the code, notice in particular the use of the Self keyword as both the parameter of the Create method (to specify the component's owner) and the value of the Parent property. I'll discuss these two elements (ownership and the Parent property) in Chapter 4, "Core Library Classes."
When writing code like this, you might be tempted to use the Form1 variable instead of Self. In this specific example, that change wouldn't make any practical difference; but if there are multiple instances of a form, using Form1 would be an error. In fact, if the Form1 variable refers to the first form of that type being created, then by clicking in another form of the same type, the new button will always be displayed in the first form. The button's Owner and Parent will be Form1, not the form the user has clicked. In general, referring to a particular instance of a class when the current object is required is bad OOP practice.
|Copyright © 2004-2021 "Delphi Sources" by BrokenByte Software. Delphi Programming Guide||