Skrypt powstał na podstawie strony Nowiesza [tutaj] (to pochylone to skopiowane), Żółtej Księgi (wszelkie cytaty z niej zostały tutaj umieszczony wyłącznie dla celów informacyjnych :P) oraz własnych przemyśleń.
Słać tutaj: malinowskirafal(at)wp(dot)pl
Projekt to program lub biblioteka łączona dynamicznie. Składa się z:
Żeby dołączyć w środowisku Delphi kod obsługi zdarzenia komponentu trzeba wybrać komponent, przejść na zakładkę Events w okienku Object Inspector i kliknąć dwukrotnie wybrane zdarzenie. Wtedy w module związanym z daną formatką (na której jest wybrany komponent) dodana zostanie metoda - pojawi się jej szkielet, w której można wpisać kod obsługi zdarzenia. Tą metodę można też wpisać ręcznie (trzeba znać parametry przekazywane do obsługi zdarzenia) i później powiązać ją z wybranym zdarzeniem.
Bezpośrenio lub pośrednio (za pomocą specjalnych metod). Z dostępem bezpośrednim mamy do czynienia gdy specyfikatory read write odnoszą sie bezpośrednio do pól obiektu, a z pośrednia - gdy odwołują się do specjalnych metod.
Z punktu widzenia programisty własności są zwykłymi polami i zmienia się wartości poprzez zwykłe przypisanie.
Ale uwaga: własności nie służą do przechowywania danych, a jedynie określają sposób ich wymiany z obiektem (i ewentualnie przedstawiają czynności wykonywane podczas tej wymiany).
program nazwa programu {$APPTYPE CONSOLE} deklaracje-modułów część opisowa begin ciąg instrukcji end.
program nazwa programu uses Forms, nazwa-modułu-formatki in 'nazwa-pliku-modułu-formatki'; [może być wiele takich linijek] {$R *.RES} begin Application.Initialize; Application.CreateForm(nazwa-klasy-formatki, nazwa-obiektu-formatki); [może być wiele takich linijek] Application.Run end.
type identyfikator-typu = record lista-deklaracji-pól end
Gdzie każda z deklaracji-pól ma postać:
lista-nazw-pól: opis-typu
a ostatnia deklaracja moze mieć postać (deklaracja wariantowa):
case deklaracja-pola-wyróżnikowego of wykaz-wariantów
lub
case identyfikator-typu-porządkowego of wykaz-wariantów
przy czym deklaracja-pola-wyróznikowego wygląda następująca:
identyfikator-pola-wyróżnikowego: identyfikator-typu-porządkowego
a każdy element wykazu-wariantów ma postać:
lista-etykiet-wybory: (lista-deklaracji-pol)
type funkcja = function (d: Double): Boolean;
i zadeklarowano zmienne:
var f : funkcja; wsk : Pointer;
Co zostanie przypisane zmiennej f po wykonaniu instrukcj:
f:=funkcja(wsk);
a co spowoduje wykonanie instrukcji
funkcja(wsk):=f;
Przy wykonaniu f:=funkcja(wsk) zostanie przypisana do zmiennej f wartość wskaźnika wsk. Natomiast wykonując funkcja(wsk):=f do zmiennej wskaźnikowej wsk zostanie przypisany adres pamiętany w zmiennej proceduralnej f. W obu przypadkach funckja(wsk) jest zmianą typu zmiennej w odwołaniu, co po prostu umożliwia takie przypisania. Bez tego nie byłyby one możliwe, ponieważ typy wskaźników (bo obie zmienne są w rzeczystości zmiennymi wskaźnikowmyi) nie są ze sobą zgodne.
Wyrażenie z operatorem is ma postać:
zmienna-typu-klasowego is odwołanie-do-klasy
Wartością wyrażenia z operatorem is jest wartość logiczna True, gdy obiekt wskazany w wyrażeniu (określony przez zmienną typu klasowego) jest elementem klasy określonej przez odwołanie do klasy lub klasy z niej wyprowadzonej (potomnej). W przeciwnym wypadku, lub gdy zmienna-typu-klasowego ma wartość nil wartością wyrażenie jest False.
Wniosek: opertor is służy do zbadania, czy dany obiekt jest obiektem typu odwołanie-do-klasy.
Wyrażenie z operatorem as ma postać:
zmienna-typu-klasowego as odwołanie-do-klasy
Wyrażenie to pozwala zmienić typ wyspecyfikowanej zmiennej na typ określony drugim operandem, przy czym zmienna ta w dalszym ciągu będzie wskazywała na ten sam obiekt w pamięci. Zmienna określająca obiekt musi mieć albo wartość nil, albo wskazywać na obiekt typu zdefiniowanego przez odwołanie-do-klasy, albo też na obiekt typu potomnego tej klasy. W przeciwnym wypadku wystąpi warunek błędu EInvalidCast.
Wniosek: operator as służy do zamiany (w wyrażeniu tylko) typu zmiennej-typu-klasowego na odwołanie do klasy.
Ogólna postać:
if wyrażenie then instrukcja
lub
if wyrażenie then instrukcja else instrukcja
UWAGA: przed else nie ma średnika, nie może być. Wartością wyrażenie powinna być wartość logiczna True lub False. Instrukcja występująca po słowie kluczowym then lub else może być dowolną instrukcją prostą lub złożoną.
Jeżeli wartością wyspecyfikowanego wyrażenia jest True, to zostanie wykonana instrukcja podana po słowie then. W przeciwnym wypadku wykonana będzie następna instrukcja po instrukcji if (gdy brak jednostki else) lub instrukcja podana po słowie else (po tym else i tak zostnaie wykonana następna instrukcja po instrukcji if - mała nielogiczność w tekście książki :P).
for zmienna:=wyrażenie-1 to wyrażenie-2 do instrukcja for zmienna:=wyrażenie-1 downto wyrażenie-2 do instrukcja
Wykonanie:
Przestudiujcie tą definicję porządnie, bo dhAM zawsze przy niej ostro chrząka i będzie wymagał jej dość dokładnie.
Przez nazwę. W tablicy nazw odpowiedniej biblioteki DLL będzie poszkiwany identyfikato danej procedury lub funkcji (po przekształceniu wszystkich małych liter na wielkie). Dyrektywa external ma postać:
external nazwa-biblioteki procedure proc_a; external 'PROCDLL.DLL';
Poprzez nową nazwę. W takim wypadku należy dodatkowo podać nazwę eksportową procedury lub funkcji w danej bibliotece, która zarazem jest nazwą importową w programie (module, bieżącej bibliotece DLL). Nazwę tę podaje się po słowie (dyrektywie języka) name. Dyrektywa external ma postać:
external nazwa-biblioteki name nazwa-importowa function podzielnik(a, b: Longint): Longint; external 'NUMLIB.DLL'; name 'NWP';
Poprzez liczbę porządkową. Jest on najbardziej efektywny, gdyż w tym wypadku odpowiedni identyfikator nie jest poszukiwany w tablicy nazw biblioteki. Liczba porządkowa procedury lub funkcji jest w bibliotece DLL ustalona za pomocą klauzuli exports. Dyrektywa external ma postać:
external nazwa-biblioteki index liczba-porządkowa procedure proc_a; external 'PROCDLL.DLL' index 15;
Deklaracje parametrów przekazywanych przez stałe i zmienne nieokreślonego typu mają postać odpowiednio:
var lista-parametrów const lista-parametrów
Parametry nieokreślonego typu służą głownie do konstrukcji procedur i funkcji przetwarzających podobne struktury danych, ale o różnych rozmiarach.
Dodam, że są to dość dziwne parametry. Nie są zgodne z żadnym typem, ich użycie jest jedynie możliwe przez zmianę typu zmiennej w odwołaniu. Różnią się od parametrych otwartych znacznie. Argumentami, odpowiadającymi parametrom nieokreślonego typu mogą być zmienne (lub wyrażenia) dowolnego typu. Natomiast argumentami odpowiadającymi parametrom otwartym są tablice (ewentualnie pojedyńcza zmienna) dowolnej wielkości, ale określonego typu.
program Egzamin; {$APPTYPE CONSOLE} uses SysUtils; var w, w1 : Variant; i : Integer; begin w:=VarArrayCreate([1,4],varVariant); w[1]:='Object'; w[2]:=False; w[3]:=1.2; w[4]:=2; for i:=1 to 4 do Writeln(w[i]); w1:=w; w[4]:=VarArrayCreate([1,4],varVariant); w[4]:=w1; for i:=1 to 3 do Writeln(w[i]); for i:=1 to 4 do Writeln(w[4][i]); Readln end.
Na ekranie zostanie wypisane:
Object 0 1,2 2 Object 0 1,2 Object 0 1,2 2
Warto przy tym zauważyć, że wszystkie elementy tablicy wariantowej (jak i wszystkie zmienne wariantowe) są wypisane w dziwnie ludzkim języku. Zamiast FALSE pojawiło się po prostu 0 oraz zamiast 1.20000000000000E+0000 pokazało się 1,2 (z przecinkiem, a nie kropką - to podobno zależy od ustawień regionalnych).
Jak na mój gust to różnica jest duża. Formatka (str.23) to okienko, na którym w procesie tworzenia programu można umieszczać różne komponenty i związany jest z nią pewien moduł programowy. Komponent (str.23) to element łącza użytkownika umieszczany na formatce (lub z nią powiązany) i jest reprezentowany przez obiekt programowy.
Warto zapamiętać, że są łańcuchy krótkie definiowane przez samo słowo kluczowe string przy dyrektywie $H-, albo też przez string[rozmiar] lub identyfikator ShortString, niezależnie od stanu dyrektywy $H. Natomiast łańcuchy długie definiuje się przez słowo kluczowe string przy $H+ lub przez identyfikator AnsiString (niezależnie od $H).
Typ Variant to typ, którego elementy mogą zmieniać się podczas wykonywania programu.
Sprawdzenie aktualnego typu można dokonać używając funkcji VarType:
if VarType(wariant) and stała = stała then ...
gdzie stała określa kod typu wariantu, który jest złożony ze stałych o przedrostku var
Sprawdzenie czy zmienna nie jest tablicą uzyskuje się poprzez:
if VarType(wariant) or varTypeMask = varTypeMask then ...
var xyz: function(a: Extended): Extended;
Przypisanie:
xyz:=Sin;
jest błędne (dlaczego?). Co należy zrobić, aby zmienna xyz oznaczała funkcję standardową Sin?
Przypisanie jest niemożliwe ponieważ do zmiennych poceduralnych nie można przypisywać procedur i funkcji z modułu System. Żeby zrealizować cel należy zdefiniować frunkcję:
function Sin(x: Extended): Extended; begin Sin:=System.Sin(x); end;
Wtedy można przypisać xyz:=Sin;
Rozmawiałem z dhAM i najważniejsze dla niego jest to, że każdy element definicji wyrażenia (chodzi mi o składnik, wyr.proste, wyrażenie) jest albo samym elementem stopnia niższego (dla składnika jest to czynnik, ...) albo połączeniem tych elementów odpowiednimi operatorami (dla składnika jest to operator multyplikatywny, ...). Jeśli chodzi o definicję czynnika to wystarczy wymienić najważniejsze (nie wszystko, ale byle bez błędów). Myślę, że najważeniejsze to: odwołanie do zmiennej, wyrażenie w nawiasach, stała bez znaku, czynnik poprzdzony +,-,not, wywołanie funkcji. Oczywiście definicję (lekko okrojoną) należy przedstawić w rekurencyjnej postaci (jak w książce), a przypadkiem nie tak jak przeze mnie (bo to nie jest definicja).
W ogólności wyrażenie jest zbudowane z czycnników, składników i wyrażeń prostych.
Czynnik to:
Składnik to: czynnik lub połaczenie dwu lub większej liczby czynników operatorem multiplikatywnymc (* / div mod and shl shr as).
Wyrażenie proste: jest to składnik lub połączenie dwu lub większej liczby skłądników operaotem addtywnym (+ - or xor).
Wyrażenie to wyrażenie proste lub połączenie dwu wyrażen prostych operatorem relacyjnym (< <= = > >= <> in is).
Konstruktory są specjalnym rodzajem metod (definiowanymi przy pomocy constructor), które służą do utworzenia i zainicjowania nowego obiektu. Inicjowanie polega na przekazaniu poprzez parametry różnych wartości do konstruktowa. W przeciwieństwie do zwykłych metod, które wywołuje się przez odwołanie do obiektu, konstruktor może być wywołany zarówno przez odwołanie do obiektu jak i przez odwołanie do klasy.
zmienna-obiektowa:=typ-klasowy.nazwa-konstruktora(lista-parametów)
Lista-parametrów jest opcjonalna - zależy od konstruktora.
type x = array[-2..10,'a'..'z'] of Double; var z = array[Boolean] of array[-10..-1] of Integer;
Po pierwsze nie ma różnicy czy identyfikator jest typem, czy zmienną danego typu - funkcje High i Low zachowują się tak samo. Po drugie High i Low zwracają największą i najmniejszą wartość jakie może przyjąć zmienna podanego typu, a dla tablic zwracają największy i najmniejszy indeks tablicy. Po trzecie te funkcje zwracają wartość typu zgodnego z podanym jako parametr. Jeśli podana zmienna/typ jest tablicą to zwracają wartość zgodną z typem indeksowym tej tablicy. Może być to liczba, znak, True, False lub identyfikator typu wyliczeniowego. Jeśli chodzi o tablicę dwuwymiarową to wygląda to tak: array [-2..10,'a'..'z'] of Double jest tym samym co array [-2..10] of array ['a'..'z'] of Double a to jest array [-2..10] of COŚTAM, - nie interesuje nas czego to jest tablica (nieważne, że jej elementy to też tablice). Podobnie z drugą tablicą: array [Boolean] of array[-10..-1] of Integer to jest array [Boolean] of COŚTAM - analogicznie j.w. Czy już wiecie co będzie wynikiem?