Rozdział 3
Elementy składowe aplikacji
Książka niniejsza nie jest przeznaczona dla początkujących, autor uznał jednak za
stosowne zamieścić tutaj zwięzłe omówienie elementów, z których składa się
każda aplikacja Delphi. Czytelnicy mogą dysponować doświadczeniami
wyniesionymi z kontaktów z innymi narzędziami programistycznymi, znacząco
różniącymi się od Delphi. W takim przypadku zbiór podstawowych informacji
o języku i środowisku Delphi pozwoli im lepiej przyswoić dalsze części książki.
Czytelnicy, którzy znają już Delphi i samodzielnie tworzyli aplikacje w tym
środowisku, mogą pominąć niniejszy rozdział i od razu przejść do rozdziału 4,
„Konwencje”.
Bieżący rozdział prezentuje koncepcję projektów i bibliotek Delphi. Zaznajamia
ponadto z elementami języka Object Pascal: modułami (ang. unit), formularzami,
modułami danych i dołączanymi plikami źródłowymi (ang. include files). Ponadto
zawarto w nim omówienie komponentów Delphi, stanowiących kluczowy element
każdej aplikacji Delphi.
Czym są projekty?
Termin „projekt” może mieć różne znaczenia, w zależności od używanego
narzędzia programistycznego. Zazwyczaj projektem nazywa się nadrzędną
strukturę, grupującą wszystkie obiekty tworzące aplikację. Główną funkcją takiej
struktury jest ustanawianie wzajemnych relacji między tymi obiektami.
Pojedynczy projekt służy z reguły za „magazyn” obiektów, należących do jednej
aplikacji. Oczywiście występują wyjątki od tej reguły. Czasami na aplikację składa
się kilka projektów. Może się również zdarzyć, że jeden projekt obejmuje kilka
aplikacji. Jednak w przypadku większości narzędzi programistycznych z pojedyn-
czego projektu generowany jest jeden wynikowy plik wykonywalny.
Projekty Delphi
W przypadku Delphi projekt zawiera listę wszystkich plików, które składają się na
jedną aplikację. Projekty Delphi wyróżniają się tym, że poza wyszczególnieniem
w nich plików źródłowych aplikacji, same także mają postać tekstu źródłowego
programu. Oznacza to, iż projekt Delphi jest programem napisanym w języku
Object Pascal, dającym się w razie potrzeby przeglądać i modyfikować.
74
Część I
UWAGA:
Możliwe jest wprawdzie ręczne modyfikowanie projektów Delphi, należy jednak
zdecydowanie unikać samodzielnego wprowadzania zmian. Delphi w trakcie pracy
nad aplikacją modyfikuje części pliku, dlatego użytkownik nie powinien zmieniać
go niezależnie, na własną rękę. Wprowadzona zmiana może zmylić Delphi; z kolei
Delphi może zamazać zmiany wpisane przez użytkownika.
Projekty Delphi mają postać tekstu programu i przechowywane są przez system
operacyjny jako pliki. Dlatego też ograniczenia co do nazw projektów, pokrywają
się z ograniczeniami nazw wszelkich identyfikatorów w języku Object Pascal.
Nazwy projektów i modułów muszą rozpoczynać się literą i mogą zawierać litery,
cyfry i znaki podkreślenia. Nie są dozwolone spacje i kropki. Listing 3.1
przedstawia niewielki plik projektu Delphi.
UWAGA:
Oczywiście maksymalna długość nazwy pliku projektu ograniczona jest z drugiej
strony przez system operacyjny. Niektóre sieciowe systemy operacyjne,
w szczególności NetWare 3.x, nie dopuszczają stosowania długich nazw plików.
To samo ograniczenie obowiązuje w niektórych systemach kontroli wersji. Przy
nadawaniu nazw plikom należy zatem brać pod uwagę również takie zewnętrzne
ograniczenia.
Listing 3.1. Plik projektu RENTMAN.
Program RENTMAN
uses
Forms
RETDATA in ‘RENTDATA.pas’ {dmRENTMAN: TDataModule},
ANYFORM in ‘..\..\CH09\CODE\ANYFORM.pas’{fmAnyForm},
DBFORM in ‘..\..\CH09\CODE\DBFORM.pas’ {fmDatabaseForm},
EDITFORM in ‘..\..\CH09\CODE\EDITFORM.pas’ {fmEditForm},
REMPENT0 in ‘REMPENT0.pas’ {fmREMPENT0},
RSYSMAN0 in ‘RSYSMAN0.pas’ {fmRSYSMAN0},
RWKTENT0 in ‘RWKTENT0.pas’ {fmRWKTENT0},
CGRDFORM in ‘..\..\CH09\CODE\CGRDFORM.pas’
➥
{fmControlGridForm},
RTENCGD0 in ‘RTENCGD0.pas’ {fmRTENCGD0},
RPROCGD0 in ‘RPROCGD0.pas’ {fmRPROCGD0},
RLEACGD0 in ‘RLEACGD0.pas’ {fmRLEACGD0},
MSTRFORM in ‘MSTRFORM.pas’ {fmMasterDetailForm}
GRIDFORM in ‘GRIDFORM.pas’ {fmGridForm},
RWORGRD0 in ‘RWORGRD0.pas’ {fmRWORGRD0},
RWORMDE0 in ‘RWORMDE0.pas’ {fmRWORMDE0},
RCALGRD0 in ‘RCALGRD0.pas’ {fmRCALGRD0},
RCALEDT0 in ‘RCALEDT0.pas’ {fmRCALEDT0},
RPROLST0 in ‘RPROLST0.pas’ {fmRPROLST0},
Błąd! Nie zdefiniowano stylu. Elementy składowe aplikacji
75
{$ *.RES}
begin
Application.Initialize;
Application.HelpFile := ‘C:\Data\Word\CSD\CH13
➥
\code\Rentman.hlp’;
Application.CreateForm(TfRSYSMAN0, fmRSYSMAN0);
Application.CreateForm(TdmRENTMAN, dmRENTMAN);
Application.CreateForm(TfmREMPENT0, fmREMPENT0);
Application.CreateForm(TfmRWKTENT0, fmRWKTENT0);
Application.CreateForm(TfmRTENCGD0, fmRTENCGD0);
Application.CreateForm(TfmRPROCGD0, fmRPROCGD0);
Application.CreateForm(TfmRLEACGD0, fmRLEACGD0);
Application.CreateForm(TfmRWORGRD0, fmRWORGRD0);
Application.CreateForm(TfmRWORMDE0, fmRWORMDE0);
Application.CreateForm(TfmRCALGRD0, fmRCALGRD0);
Application.CreateForm(TfmRCALEDT0, fmRCALEDT0);
Application.CreateForm(TfmRPROLST0, fmRPROLST0);
Application.Run;
end.
Słowo kluczowe program
Słowo kluczowe
program
, rozpoczynające listing 3.1, informuje kompilator, że
na podstawie tego pliku źródłowego ma być wygenerowany osobny plik
wykonywalny. W przypadku biblioteki dołączanej dynamicznie (DLL) albo
modułu, słowo
program
zastępowane jest odpowiednio przez słowo
library
albo
unit
.
Polecenie uses
W ramach polecenia
uses
wymienione są wszystkie moduły, napisane w języku
Object Pascal, które Delphi skonsoliduje (połączy), tworząc plik wykonywalny.
Moduły (ang. units) są elementami, składającymi się na aplikację Delphi. Gdy
użytkownik zleca skompilowanie lub uruchomienie pliku projektu, Delphi
automatycznie rekompiluje każdy moduł, którego kod wynikowy jest starszy niż
aktualny tekst źródłowy. W niektórych środowiskach programowania za proces ten
odpowiada program (lub funkcja) make.
Moduł
Forms
, wymieniony na listingu 3.1, stanowi część biblioteki Visual
Component Library, wchodzącej w skład pakietu Delphi. Pozostałe moduły,
wymienione na listingu, odpowiadają formularzom, dodanym do projektu przez
autora aplikacji. W każdym wierszu wymienione są kolejno: nazwa modułu,
ścieżka dostępu do pliku, w którym ten moduł jest przechowywany oraz nazwa
formularza, zawartego w module. Nazwy formularzy odpowiadają identyfikatorom
wpisywanym w
polu atrybutu
Name
, w
oknie Object Inspector. Wraz
z wprowadzeniem w Delphi obsługi długich nazw plików, możliwe stało się
76
Część I
nadawanie plikom nazw identycznych z nazwami modułów. Oczywiście nazwa
modułu nie zawiera rozszerzenia. Jeśli podczas kompilacji Delphi nie jest w stanie
zlokalizować modułu, korzystając z
jego długiej nazwy, podejmuje próbę
odszukania go na podstawie nazwy skróconej.
Dyrektywa $R
Dyrektywa kompilatora
$R
interpretowana jest jako polecenie dołączenia do
projektu wskazanego pliku zasobów Windows. Gwiazdka oznacza, że główna
część nazwy pliku zasobów jest identyczna z
nazwą projektu. W
trakcie
budowania projektu Delphi tworzy plik zasobów dla samego projektu oraz dla
każdego z zawartych w nim formularzy. Jeśli któryś z plików zasobów nie jest
dostępny podczas konsolidacji programu, Delphi generuje komunikat „
File not
found: xxx.RES
”.
Application.CreateForm
Polecenia
Application.CreateForm
wczytują formularze, należące do
projektu, do pamięci operacyjnej. Na ogół wymienione są w ten sposób wszystkie
formularze, zawarte w projekcie. Korzystając z opcji menu
Options\Project
, można
zdecydować, które formularze mają być tworzone automatycznie. Każdy
utworzony formularz przechowywany jest w zmiennej. Zmienna taka - na przykład
fmRSYSMAN0
- zdefiniowana jest w sekcji
interface
modułu formularza.
Ponieważ projekt wykorzystuje moduły a one z kolei definiują powyższe zmienne,
na poziomie projektu „widać” te zmienne i można przekazać je jako argument
wywołania procedury
Application.CreateForm
. Procedura ta tworzy
wskazany formularz w pamięci i zwraca w zmiennej do niego wskaźnik.
Kolejność, w
jakiej formularze wymienione są w
ciągu wywołań
Application. CreateForm
, określa kolejność tworzenia formularzy.
Pierwszy formularz, utworzony przez
Application. CreateForm
, staje się
głównym formularzem aplikacji. Chcąc zmienić kolejność tworzenia formularzy,
należy skorzystać z opcji menu
Options\Application
; nie należy natomiast zmieniać
tekstu źródłowego projektu.
Application.Run
Wywołanie
Application.Run
powoduje wejście do głównej pętli aplikacji,
czyli faktyczne uruchomienie programu.
Błąd! Nie zdefiniowano stylu. Elementy składowe aplikacji
77
Biblioteki Delphi
Delphi oferuje wygodny mechanizm tworzenia bibliotek dołączanych dynamicznie
(ang. dynamic link libraries, DLL). W przeciwieństwie do większości innych
języków programowania w Windows, Delphi dysponuje specjalnymi elementami
składni, wspomagającymi generowanie bibliotek DLL. Należą do nich dwa słowa
kluczowe:
library
i
export
. Słowo kluczowe
library
zastępuje słowo
program
, obecne w
poprzednim przykładzie. Informuje kompilator, że
generowana ma być biblioteka DLL, a nie plik EXE. Użycie słowa kluczowego
export
powoduje wyeksportowanie wskazanych funkcji z biblioteki DLL;
eksportowane funkcje biblioteczne mogą być wywoływane z innych modułów
wykonywalnych. Na Listingu 3.2 przedstawiono tekst źródłowy niewielkiej
biblioteki.
Listing 3.2. Biblioteka StrUtil.
library StrUtil;
Uses
SysUtils;
function Pad(InString: String; Len: Integer): String;
begin
Result:=Format(‘%-*s’,[Len, InString]);
end;
function LPad(InString: String; Len: Integer): String;
begin
Result:=Format(‘%*s’,[Len, InString]);
end;
exports
Pad index 1,
LPad index 2;
begin
end.
Biblioteki mają formę bardzo zbliżoną do programów. Należy jedynie zwrócić
uwagę na słowo
library
, zastępujące słowo
Program
(zob. początek Listingu
3.2). Polecenie
exports
nakazuje wyeksportowanie funkcji
Pad
i
LPad
z biblioteki DLL. Funkcje te będzie można wywoływać z innych modułów
wykonywalnych.
Moduły (ang. units) w Delphi
Moduły stanowią - obok formularzy - elementarne bloki, składające się na
aplikację Delphi. W
modułach przechowywane są definicje formularzy,
decydujących o
graficznej postaci aplikacji. Moduły zawierają ponadto
dodatkowe, dopisywane przez autora programu, fragmenty kodu, wspomagające
funkcje aplikacji.
78
Część I
Każdemu formularzowi, dodawanemu do projektu, towarzyszy oddzielny plik
źródłowy modułu. Plik taki zawiera definicję klasy, która odpowiada wizualnej
reprezentacji formularza. Gdy autor doda do formularza jakikolwiek komponent,
Delphi automatycznie modyfikuje definicję klasy, tak aby obejmowała ona ten
nowy komponent. Również każdy dodany do formularza podprogram obsługi
zdarzenia przechowywany jest w pliku modułu. Zdecydowana większość tekstu
programu, dopisywana samodzielnie przez autora aplikacji, trafia właśnie do
plików modułów. Listing 3.3 przedstawia tekst źródłowy prostego modułu.
Listing 3.3. Tekst źródłowy modułu Delphi.
Unit RTENCGD0;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, CGRDFORM, Buttons, DBCtrls, StdCtrls,
ExtCtrls, Mask, DBNavSch, DBCGrids;
type
TfmRTENCGD0 = class(TfmControlGridForm)
teTenantNo: TDBText;
deName: TDBEdit;
deEmployer: TDBEdit;
deEmpAddress: TDBEdit;
deEmpCity: TDBEdit;
deEmpState: TDBEdit;
deEmpZip: TDBEdit;
deHomePhone: TDBEdit;
deWorkPhone: TDBEdit;
deICEPhone: TDBEdit;
deLeaseBeginDate: TDBEdit;
deLeaseEndDate: TDBEdit;
deMovedInDate: TDBEdit;
deMovedOutDate: TDBEdit;
deRentDueDay: TDBEdit;
dePetDeposit: TDBEdit;
deComments: TDBEdit;
Label1: TLabel;
dkLawnService: TDBCheckBox;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
Label9: TLabel;
Label10: TLabel;
LaName: TLabel;
Label12: TLabel;
Label13: TLabel;
Label14: TLabel;
Label15: TLabel;
Błąd! Nie zdefiniowano stylu. Elementy składowe aplikacji
79
Label16: TLabel;
Label17: TLabel;
private
{ Private declarations }
public
( Public declarations }
end;
var
fmRTENCGD0: TfmRTENCGD0;
DefaultPetDeposit : Integer;
implementation
uses rentdata;
{$R *.DFM}
initialization
DefaultPetDeposit:=150;
end.
Sekcja interface
Przede wszystkim należy zwrócić uwagę na podział modułu na sekcje
interface
,
implementation
i
initialization
. Sekcja
interface
zawiera informacje nagłówkowe modułu. Obejmują one deklaracje funkcji
i procedur oraz definicje zmiennych, stałych i typów, które mają być widoczne na
zewnątrz modułu. Sekcja ta odpowiada plikowi nagłówkowemu programu
w języku C. Inaczej niż w języku C, informacji nagłówkowych modułów Delphi
nie trzeba przechowywać w osobnym pliku źródłowym, który musiałby być
dołączany do wszystkich innych modułów dyrektywą
include
lub jej
odpowiednikiem. Informacje nagłówkowe przechowywane są w skompilowanym
pliku modułu. Gdy jakiś inny moduł odwołuje się do niego poprzez polecenie
Uses
, Delphi - chcąc pobrać informacje o deklaracjach i definicjach - odczytuje
nagłówek skompilowanego modułu, a nie jego tekst źródłowy.
Powyższe rozwiązanie umożliwia dystrybucję modułów w postaci skompilowanej,
bez konieczności dodawania do nich jakichkolwiek plików nagłówkowych.
Eliminuje ponadto każdorazową rekompilację pliku nagłówkowego, towarzysząca
kompilacji zawierającego go modułu (ten ostatni problem rozwiązują tzw.
prekompilowane pliki nagłówkowe - ang. precompiled headers - które jednak nie
są dostępne we wszystkich kompilatorach języka C).
80
Część I
Sekcja implementation
Sekcja
implementation
zawiera właściwy tekst podprogramów, zawartych
w module. Wszystkie obiekty programu, umieszczone w tej sekcji, nie będą
widoczne poza modułem, o ile nie zostały wymienione w sekcji
interface
.
W typowym module deklaracje funkcji umieszczane są w sekcji
interface
,
natomiast ich treść w sekcji
implementation
.
Zmienna identyfikująca formularz
Wśród definicji zmiennych (po słowie
var
) w sekcji
interface
występuje
zmienna, identyfikująca egzemplarz formularza:
var
fmRTENCGD0: TfmRTENCGD0;
Zdefiniowano w
ten sposób zmienną o
nazwie
fmRTENCGD0
, typu
TfmRTENCGD0
.
TfmRTENCGD0
jest typem potomnym w stosunku do
TForm
i został automatycznie zdefiniowany podczas interaktywnego tworzenia formularza
w środowisku Delphi. Zmienna
fmRTENCGD0
jest inicjowana w pliku projektu,
podczas wywołania
Application.CreateForm
. Ponieważ zmienna ta jest
zdefiniowana w
sekcji
interface
modułu, jest widoczna i
może być
modyfikowana we wszystkich innych modułach, odwołujących się do niego
w swoich klauzulach
Uses
, w tym także w pliku projektu.
Sekcja initialization
W sekcji tej należy umieszczać fragmenty programu, które mają być wykonane
bezpośrednio po pierwszym załadowaniu modułu. Kod sekcji
initialization
wykonywany jest zatem po załadowaniu aplikacji. Kolejność wykonywania sekcji
initialization
poszczególnych modułów odpowiada kolejności w jakiej
moduły te są wymienione w poleceniu
Uses
pliku projektu. Na Listingu 3.3
sekcja
initialization
obejmuje wiersze pomiędzy słowem
initialization
, a końcem modułu:
initialization
DefaultPetDeposit:=150;
end.
Po załadowaniu aplikacji, zmienna
DefaultPetDeposit
jest inicjowana
wartością 150. Aplikacja może później odwoływać się do zmiennej, mając
gwarancję, że ta została już poprawnie zainicjowana.
Błąd! Nie zdefiniowano stylu. Elementy składowe aplikacji
81
Sekcja finalization
W module można dodatkowo umieścić sekcję
finalization
. Program, zawarty
w tej sekcji, wykonywany jest przy zamykaniu aplikacji. Typowe czynności,
wykonywane w sekcji
finalization
, obejmują zamykanie otwartych plików
i
zwalnianie wszelkich innych zasobów, z
których moduł mógł korzystać.
Omawiana sekcja musi występować po sekcji
initialization
, ale przed
ostatnim słowem kluczowym
end.
modułu.
Formularze Delphi
Formularze Delphi są elementami, odpowiadającymi za wizualną postać aplikacji.
Większość operacji, wykonywanych w trakcie interaktywnego projektowania
formularzy w środowisku Delphi, znajduje swoje odbicie w pliku formularza.
Zmiana atrybutu albo przesunięcie komponentu sprowadza się w istocie do zmiany
wybranych ustawień, przechowywanych w pliku formularza.
Ponieważ narzędzia programistyczne Delphi dynamicznie łączą mechanizmy
programowania wizualnego z tradycyjnym pisaniem kodu, możliwa jest edycja
formularza w postaci tekstowej. Po jego zapisaniu można obejrzeć efekty
poczynionych zmian w postaci graficznej. Listing 3.4. przedstawia tekstową
wersję niewielkiego formularza.
Listing 3.4. Reprezentacja tekstowa prostego formularza
inherited fmDatabaseForm: TfmDatabaseForm
Left = 75
Top = 124
Width = 554
Caption = ‘fmDatabaseForm’
PixelsPerInch = 96
TextHeight = 13
inherited paTop: TPanel
Width = 546
end
inherited paMiddle: TPanel
Width = 546
end
inherited paBottom: TPanel
Width =546
object paRight: TPanel
Left = 385
Top = 1
Width = 160
Height = 37
Align = alRight
BevelOuter = bvNone
TabOrder = 0
object bbok: TBitBtn
82
Część I
Left = 4
Top = 8
Width = 75
Height =25
TabOrder = 0
Kind = bkOK
end
object bbCancel: TBitBtn
Left = 82
Top = 8
Width = 75
Height = 25
TabOrder = 1
Kind = bkCancel
end
end
object bbPrintForm: TBitBtn
Left = 280
Top = 8
Width = 75
Height = 25
Caption = ‘Print Form’
TabOrder = 1
OnClick = bbPrintFormClick
Glyph.Data = {
76010000424D760100000000000076000000280000002000000
➥
0100000000100
04000000000000010000130B0000130B0000000000000000000
➥
0000000000000
800000800000008080008000000080008000808000007F7F7F0
➥
0BFBFBF000000
FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF0
➥
0300000000000
00033FFFFFFFFFFFFFFF0888888888888880777777777777777
➥
F088888888888
8880777777777777777F0000000000000000FFFFFFFFFFFFFFF
➥
F0F8F8F8F8F8F
8F80777777777777777F08F8F8F8F8F8F9F0777777777777777
➥
F0F8F8F8F8F8F
8F807777777777777F7F0000000000000000777777777777777
➥
F3330FFFFFFFF
03333337F3FFFF3F7F333330F0000F0F03333337F77773737F3
➥
33330FFFFFFFF
03333337F3FF3FFF7F333330F00F000003333337F7737777733
➥
33330FFFF0FF0
33333337F3FF7F3733333330F08F0F0333333337F7737F73333
➥
33330FFFF0033
Błąd! Nie zdefiniowano stylu. Elementy składowe aplikacji
83
33333337FFFF773333333330000003333333333777777333333
➥
3}
NumGlyphs = 2
end
object DBNavigator1: TDBNavSearch
Left = 8
Top = 8
Width = 253
Height = 25
TabOrder =2
end
end
end
Moduły danych
Delphi umożliwia korzystanie ze specjalnych formularzy, zwanych modułami
danych (ang. data modules). Tworzy się je przy pomocy polecenia
New Data
Module
z menu
File
. Moduły danych umożliwiają grupowanie kontrolek nie
posiadających reprezentacji graficznej - zwykle komponentów obsługujących bazy
danych - na pojedynczym, centralnym formularzu. Pozostałe formularze, chcąc
uzyskać dostęp do komponentów obsługujących bazę danych, odwołują się do
modułów danych. Moduły danych można także umieszczać w składnicy obiektów
Delphi (Object Repository) i tworzyć na ich podstawie formularze potomne,
kopiować je i wykorzystywać, tak jak wszelkie inne obiekty, przechowywane
w składnicy. Należy zwrócić uwagę, że na module danych nie można umieścić
kontrolki graficznej.
Dołączane pliki źródłowe (ang. include files)
Podobnie, jak większość narzędzi programistycznych, kompilator Delphi
umożliwia dołączanie zewnętrznych plików źródłowych (tzw. include files) na
etapie kompilacji. Mechanizm ten umożliwia wykorzystywanie tych samych
fragmentów programu źródłowego w różnych częściach aplikacji. Należy jednak
pamiętać, że Delphi każdorazowo po napotkaniu dyrektywy dołączenia w danym
miejscu zewnętrznego pliku źródłowego, kompiluje ten plik. Dlatego też należy
ograniczać stosowanie dołączanych plików źródłowych, a
zamiast nich
wykorzystywać moduły (units).
W praktyce dołączane pliki źródłowe zawierają na ogół szereg dyrektyw dla
kompilatora; dyrektywy te mają być zastosowane do wszystkich modułów,
należących do projektu. Plik z dyrektywami dołączany jest jako zewnętrzny plik
źródłowy do wszystkich modułów. Po jego zmianie, czyli zmianie dyrektyw dla
kompilatora, wszystkie moduły są poddawane rekompilacji. Poniższy listing
84
Część I
przedstawia przykład takiego pliku z
dyrektywami, zaczerpnięty z
tekstu
źródłowego programu WinMac32 Windows Macro Engine:
{$B-,F-,G+,I-,K+,N-,P+,Q-,R-,S+,T-,V+,W-,X+}
{$IFNDEF DEBUG}
{$D-}
{$ELSE}
{$D+,L+,Y+}
{$ENDIF}
UWAGA:
Kompletny tekst źródłowy WinMac32 znajduje się na płycie CD-ROM dołączonej
do książki.
Powyższy plik umożliwia łatwe uaktywnianie i wyłączanie opcji kompilatora,
kontrolujących poziom wspomagania programu uruchomieniowego (debuggera).
Należy zwrócić uwagę na wiersz
{$IFNDEF DEBUG}
. Informuje on kompilator,
że jeśli użytkownik nie zdefiniował o nazwy symbolicznej
DEBUG
, to trzy opcje
związane z programem uruchomieniowym -
$D
,
$L
i
$Y
- mają być wyłączone.
Wyłączenie opcji
$D
automatycznie wyłącza również dwie pozostałe.
Analogicznie, jeżeli użytkownik zdefiniował
DEBUG
, trzy opcje są uaktywnianie.
Jeśli wszystkie moduły aplikacji będą zawierały dyrektywę dołączenia tego pliku,
będzie można bardzo łatwo decydować, czy mają być kompilowane z aktywnymi
przełącznikami dotyczącymi debuggera, czy też nie - wystarczy zdefiniować lub
usunąć definicję nazwy symbolicznej
DEBUG
. Rozwiązanie to wydaje się
wygodniejsze niż przełączanie trzech opcji w polu dialogowym
Options\Project
.
Po utworzeniu pliku z dyrektywami, dołącza się go do odpowiednich plików
źródłowych modułów, korzystając z dyrektywy
$I
, na przykład:
{$I WINMAC32.INC}
UWAGA:
Warunkowe dyrektywy kompilatora nie są przenoszone między poszczególnymi
modułami, mimo że można byłoby tego oczekiwać. Rozpoczynając kompilację
nowego modułu, Delphi zawsze ustala stan dyrektyw warunkowych zgodnie
z
ustawieniami, wpisanymi w
polu dialogowym
Project\Options
albo
w parametrach wywołania kompilatora.
Komponenty Delphi
Jeśli formularze porównamy do cząsteczek, składających się na aplikację Delphi,
to komponenty wypadałoby nazwać atomami, tworzącymi te cząsteczki.
Formularze składają się zatem z komponentów.
Błąd! Nie zdefiniowano stylu. Elementy składowe aplikacji
85
Za reprezentacją graficzną komponentów, widoczną w środowisku programowania
wizualnego Delphi, kryją się fragmenty programu w języku Object Pascal. Listing
3.5 przedstawia tekst źródłowy prostego komponentu.
Listing 3.5. Tekst źródłowy nowego komponentu
- TArrayTable
{
Komponent Delphi ArrayTable
Umożliwia dostęp do tabeli w
sposób typowy dla tablic.
Aby uzyskać dostęp do wartości poszczególnych pól
należy użyć składni:
Records[RecNum].Fields[FieldNum].AsType
Autor: Ken Henderson.
Copyright (C) 1995 by Ken Henderson.
}
unit ArrayTable;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, Db, DBTables;
type
TArrayTable = class(TTable)
private
{Private declarations}
function GetRecords(RecNum : Longint) : TDataSet;
protected
{Protected declarations}
public
{Public declarations}
property Records{RecNum : Longint} : TDataSet read
➥
GetRecords;
published
{Published declarations}
end;
procedure Register;
implementation
function TArrayTable.GetRecords(RecNum : Longint) : TDataSet;
begin
First
MoveBy(RecNum);
Result:=Self;
end;
procedure Register;
begin
RegisterComponents( ‘Data Access’, [TArrayTable]);
86
Część I
end;
end.
Powyższy komponent zdefiniowano jako klasę pochodną standardowej tabeli
Table, dodając tylko jeden publiczny atrybut:
Records
. Dzięki niemu możliwe
jest traktowanie tabeli tak, jak jednej dużej tablicy. Na przykład, poniższy zapis
zwróci - w postaci łańcucha znaków - zawartość trzeciego pola z piątego rekordu
(zarówno nowy atrybut
Records
, jak i własny atrybut
Fields
klasy
TTable
wymagają indeksów liczonych od zera):
TArrayTable1.Records[4].Fields[2].AsString;
Jak nietrudno zauważyć, rozszerzenie funkcji istniejącego komponentu nie
wymagało dużego nakładu pracy. Cały proces był nawet prostszy niż tworzenie
nowego komponentu przy użyciu polecenia
New
Component
z menu
Component
.
Po wywołaniu tego polecenia, użytkownik musi wskazać klasę - przodka
(w naszym przypadku będzie to
TTable
), wprowadzić nazwę nowej klasy
i wybrać stronę palety komponentów, na której ma się znaleźć nowy komponent.
Delphi automatycznie generuje odpowiedni fragment programu.
UWAGA:
Należy zwrócić uwagę, że - choć nie widać tego wprost w tekście źródłowym
TArrayTable
- korzystanie z atrybutu
Records
zawsze powoduje fizyczne
przesunięcie wskaźnika bieżącego rekordu. Nie ma sposobu obejścia tego
ograniczenia, które wynika z właściwości mechanizmów dostępu do baz danych
w Delphi. Zapamiętanie i późniejsze odtwarzanie stanu wskaźnika wewnątrz
komponentu nie rozwiązuje problemu, gdyż atrybut
Fields
komponentu
TTable
odwołuje się zawsze do bieżącego rekordu. Dlatego zapamiętywanie
wskaźnika bieżącego rekordu w powinno odbywać się przed odwołaniem do
atrybutu
Records
, a odtwarzanie - po skorzystaniu z tego atrybutu.
Należy również zwrócić uwagę na wywołanie procedury
RegisterComponent
,
umieszczone na końcu listingu 3.5. Procedura ta dodaje komponent Delphi do
palety paska narzędzi. Pierwszy argument procedury wskazuje na stronę palety, na
której ma się znaleźć nowy komponent. Drugi argument zawiera listę
komponentów, które mają zostać zarejestrowane. Nazwy komponentów należy
oddzielać przecinkami (wewnątrz nawiasów kwadratowych).