Wstęp do programowania wizualno-obiektowego
Na czym polega wizualno-obiektowa technika programowania?
Programowanie obiektowe polega na operowaniu w programie obiektami, którymi są dane wraz z tak zwanymi metodami, które mogą zostać wykorzystane wyłącznie do ściśle określonych celów. Programowanie wizualne polega natomiast na graficznym projektowaniu programu, a dokładniej mówiąc interfejsu graficznego programu, można to przyrównać do rysowania w prostym edytorze grafiki. Końcowy efekt uzyskujemy łącząc te dwie metody programowania, poprzez powiązanie graficznie zaprojektowanych obiektów (np. formularza czy przycisków) z metodami za pomocą zdarzeń.
Zmienna obiektowa lub po prostu obiekt jest elementem pewnej klasy.
Klasa jest to typ obiektowy, który definiujemy w podobny sposób jak typ rekordowy.
Metody to po prostu funkcje i procedury programu.
Zdarzenie to dowolna akcja np. ruch myszy lub wciśnięcie jakiegoś przycisku z klawiatury.
Podstawowa różnica pomiędzy programowaniem tradycyjnym, a obiektowym polega na tym, że w programowaniu tradycyjnym przy wywołaniu procedur są przekazywane im dane, natomiast w programowaniu obiektowym aktywuje się metody dla odpowiednich danych umieszczonych w polach obiektu. W programowaniu nieobiektowym bardzo niebezpieczne jest modyfikowane istniejących struktur danych. Przy jakiejkolwiek zmianie struktury danych należy sprawdzić w calym programie konsekwencję jej wprowadzenia. W programowaniu obiektowym zmiana struktury danych ogranicza się do obiektu, którego dotyczy.
Co to jest Delphi?
System Delphi firmy Borland to nowoczesne narzędzie umożliwiające zaprojektowanie w wizualny sposób programu z wykorzystaniem wszystkich środków dostępnych w środowisku Wmdows, a następnie wykonanie tego programu również w środowisku Windows. Programowanie w systemie Delphi polega na umieszczaniu na formularzu wybranych komponentów, a następnie programowaniu w języku, będącym rozszerzeniem języka Pascal. Można zatem powiedzieć, że system Delphi jest następcą języka Pascal w środowisku Windows.
Firma Borland wyprodukowała dotąd 7 wersji Delhi: Delphi 1.0, Delphi 1.02, Delphi 2.0, Delphi3.0, Delphi 4.0, Delphi 4.0 SP1, Delphi 5.0, Delphi 6.0: Desktop, Professional, Enterprise, Client/Server, Standard, Development, Delhi 7.0 Enterprices, Architekt, Personal, Professional, czym nowsza wersja programu tym więcej procedur i funkcji on obsługuje.
Końcowy produkt pojawia się w gotowym pliku *.EXE, ale konieczne jest skompilowanie kodu źródłowego poprzez naciśnięcie "zielonego trójkąta" w głównym menu programu lub naciśnięcie klawisza F9. Kompilowanie polega na tłumaczeniu kodu źródłowego programu na język wewnętrzny komputera. Jeżeli programowałeś w innych programach w których używa się języka "pascalowskiego" z opanowanie Delphi nie będziesz miał trudności, a jeżeli nauczysz się Delphi na pewno będziesz w stanie nauczyć się innych języków programowania.
BUDOWA MODUŁU
Poniżej przedstawiony jest nowo utworzony moduł w Delphi.
Unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
end.
Nazwa pliku jaki ma być używany. (stały element)
(stały element)
Moduł. (stały element)
Moduły przez ciebie używane (są zmienne w zależności z jakich korzystamy)
W type jest wszystko jakich komponentów i procedur używamy (stały element)
Komponenty i procedury jakich używamy. (zmienne elementy w zależności z jakich kożystamy)
Prywatne deklaracje. (stały element)
Publiczne deklaracje. (stały element)
Zakończenie interface. (stały element)
Zmienne od variables. (stały element)
Nazwa formularza. (stały element)
W implementation znajdują się wszystkie procedury.
Pojedyncza procedura.
Zakończenie implementation.
W treści modułu możemy wyróżnić trzy części: opisową, implementacyjną oraz inicjującą. Część inicjująca musi kończyć się kropką.
Cześć opisowa Interface |
Definicje typów i stałych |
Definicje zmiennych |
Lista nagłówków procedur i funkcji, które mogą znaleźć |
się w części private (oznacza uniemożliwienie |
Wykorzystania ich w innych modułach) lub w części public |
(umożliwia dostęp do nich we wszystkich modułach) |
Część implementacyjna Implementation |
Definicje procedur i funkcji, których nagłówki podano w części inteface |
Część inicjująca instrukcja złożona lub słowo kluczowe end. |
Komponent jest to obiekt, który można wizualnie zaprojektować na formularzu. Własności komponentów można ustalać w specjalnym oknie właściwości o nazwie Object Inspector. Oprócz właściwości można w tym oknie podawać nazwy metod, które powinny być wykonane po zajściu określonego zdarzenia. Zdarzenie to dowolna akcja jak np. naciśnięcie klawisza myszki na przycisku lub zmiana położenia kursora myszki.
Komponenty systemu Delphi są pogrupowane na kilkanaście tzw. stron. Są to strony: podstawowa, dodatkowa, dwie strony systemowe, internetowa, strony związane z bazami danych, dialogowa i strony przykładowe. Ich liczba jest oczywiście zależna od wersji sytemu delphi.
ZMIENNE I STAŁE
Zmienne to dane, które mogą przyjmować wartości w ramach typu przypisanego lub określonego dla tych zmiennych. Mogą przyjmować wartość liczbową, tekstową lub booleanowską (prawda, fałsz). W Delphi pod zmienną można także przypisać komponenty.
Liczby całkowite:
Typ zakres wielkość. |
Liczby rzeczywiste:
Typ zakres wielkość i cyfry dokładne.
Double 5.0e-324..1.7e308 8 B 15-16 |
Wartości tekstowe:
PChar
jest to tablica znaków, w każdej chwili możemy odwołać się do dowolnego znaku.
String
jest to typ przechowujący tekst nie przekraczający 255 znaków (od Delphi 2 można rozszerzyć tę wielkość)
AnsiString
ten typ pojawił się w Delphi 2, jest o wiele lepszy od String, gdyż długość łańcucha jest praktycznie nieograniczona.
Zmienne deklarujemy przed słowem begin. Poprzedzamy je słowem var (variable - zmienna). Jak sama nazwa mówi ich wartości mogą ulegać zmianie podczas wykonywania programu. W Delphi najczęściej wykorzystuje się String, Integer, Real i Extended.
Operatory to symbole służące do manipulowania danymi. Zajmiemy się pięcioma rodzajami operatorów.
OPERATRORY
Operator przypisania (:=) służy do przypisania zmiennej wartości np.:
liczba := 5; Instrukcja przypisuje zmiennej liczba wartość 5.
Operatory porównania (=, <>, <, >, <=, >=)
Służą do stwierdzenia równości, nierówności lub porównania pod względem relacji mniejszości dwóch wartości.
if x>2 then Label1.Caption:='zmienna x jest większa od 2';
Operatory logiczne (and, or, not)
Realizują operacje wynikające z algebry Boole'a. Inaczej mówiąc testują kilka warunków, np.:
if (a=1) and (b=3) then Label1.Caption:='Coś'; - jeżeli a=1 i b=3 to...
Operatory arytmetyczne
służą do dodawania, odejmowania itd. itp. np.:x:=5+5;
Operatory zmniejszenia lub zwiększenia
powodują zwiększenie lub zmniejszenie wartości liczbowej, np.:x:=5;
Inc(x) - w wyniku otrzymamy x:=6; lub Inc(x,5) - zwiększamy x o 5, w wyniku otrzymamy x:=10;
TYP |
ZNAK |
Przypisanie |
:= |
Równe |
= |
Nierówne |
<> |
Mniejsze |
< |
Mniejsze-równe |
<= |
Większe-równe |
>= |
Logiczne "i" |
and |
Logiczne "lub" |
or |
Zaprzeczenie |
not |
TYP |
ZNAK |
Dodawanie |
+ |
Odejmowanie |
- |
Mnożenie |
* |
Dzielenie rzeczywiste |
/ |
Dzielenie całkowite |
div |
Reszta z dzielenia |
mod |
Zwiększenie |
Inc() |
Zmniejszenie |
Dec() |
PĘTLE
Pętle służą do powtarzania ustalonych czynności. W Delphi dostępne są trzy rodzaje pętli.
Pętla For
służy do powtarzania czynności określoną liczbę razy, np.:
{dodanie do Memo stu linijek tekstu}
var petla: integer;
begin
for petla:=1 to 100 do
Memo1.Lines.Add('Linia '+IntToStr(petla));
end;
Pętla While...Do
pętla służy do powtarzania danej czynności dopóki spełniany jest dany warunek, np.:
var x:integer;
begin
x:=0;
while x<10 do
x:=x+1;
end;
Pętla Repeat...Until
pętla jest podobna do while...do, tyle że warunek sprawdzany jest po wykonaniu operacji, np.:
var x:integer;
begin
x:=0;
repeat
x:=x+1;
until x<10
end;
Pętle można przerwać, gdy wystąpi jakiś warunek, funkcją Break, np.:
var petla: integer;
begin
for petla:=1 to 100 do
if petla=99 then break else
Memo1.Lines.Add('Linia '+IntToStr(petla));
end;
WYJĄTKI
Wyjątki to mechanizmy umożliwiające aplikacji powrót do normalnego działania po wystąpieniu błędu. Jest to rzecz prosta więc przejdziemy do przykładu:
var
plik: TextFile;
begin
AssignFile(plik, 'plik.abc');
try
reset(plik);
try
write('tekst');
finally
CloseFile(plik);
end;
except
ShowMessage('Błąd wejścia/wyjścia');
end;
end;
W konstrukcji "try...finally" wpierw wykonywane są operacje zawarte pomiędzy klauzulami try i finally. Po ich zakończeniu wykonywane są zadania z klauzuli finally i end, wykonywane są niezależnie od tego jaki był skutek wykonania pierwszej klauzuli. Klauzula except i end służy do obsłużenia wyjątku.
INSTRUKCJE WARUNKOWE
Instrukcje warunkowe służą do sprawdzenia, czy dany warunek jest spełniony. Jeżeli tak to wykonywana jest jakaś czynność, a jeżeli nie to jest ona ignorowana. W Delphi mamy dwie instrukcje warunkowe.
If...Then
czyli "Jeżeli...To...". Gdy warunek jest spełniony to wykonywana jest jakaś czynność, np.:
If x=1 then ....
Istnieje też druga konstrukcja tej instrukcji - If...Then...Else, czyli "Jeżeli...To...W przeciwnym wypadku...". Krótko mówiąc, gdy spełniony jest warunek zrób coś, jeżeli nie to zrób coś innego.
If x=1 then ... else ...
Case...Of
Czyli „Wybierz z”. Jeżeli napotka na taką samą wartość to jest wykonywana odpowiednia instrukcja
case x of
1: ....;
2: ....;
3:.....;
end;
np.
var x:integer;
....
Case x of
1:label1.Caption:='wartośc pierwsza';
2:label1.Caption:='wartośc druga';
3:label1.Caption:='wartośc trzecia';
4:label1.Caption:='wartośc czwarta';
end;
TABLICE
Tablice to struktury składające się z wierszy i kolumn oraz komórek do których wpisuje są różne wartości np. liczbowe, tekstowe. W każdej chwili można odczytać zawartość danej komórki (np. [5,5]). Najczęściej używanymi są tablice jedno- i dwuwymiarowe. Tablica jednowymiarowa to nic innego jak ciąg zmiennych (np: 1,2,3,4,5,6..n), natomiast tablica dwuwymiarowa to macierz, która wyglądem przypomina komponent StringGrid lub okno MS Excel.
Przykład tablicy jednowymiarowej:
var
tab: array[1...10] of integer;
x: integer;
begin
for x:=1 to 10 do begin
tab[x]:=x;
end; Label1.Caption:=IntToStr(tab[4]);
end;
Przykład tablicy dwuwymiarowej
var
tab: array[1...10, 1...10] of Integer;
x,y: Integer;
begin
for x:=1 to 10 do begin
for y:=1 to 10 do begin
tab[y,x]:=x;
end;
end; Label1.Caption:=IntToStr(tab[5,5]);
end;
Zawsze deklarujemy rozmiar tabeli (kwadratowe nawiasy). Począwszy od Delphi 4 istnieje tablica dynamiczna. Podając zmienną tablicy nie musimy podawać jej rozmiarów, robimy to dopiero w dalszej części programu korzystając z funkcji SetLength, np.:
var tab: array of integer;
begin
SetLength(tab, 10);
end;
Deklarujemy tablice, a następnie przypisujemy jej wielkość 11 elementów (komórki liczymy od 0).
PROCEDURY, FUNKCJE I MODUŁY
Podczas pisania programu często zachodzi potrzeba wykonania danej czynności w kilku miejscach (pętla, rysowanie itp.). Przydałoby się wtedy coś podobnego do zmiennej. Do tego służą procedury, funkcje i moduły. Stworzymy prostą procedurę by zrozumieć na czym polega jej działanie:
procedure Rysuj(x1, y1, x2, y2: Integer; kolor: TColor);
begin
Form1.Canvas.Brush.Color:=kolor;
Form1.Canvas.Rectangle(x1, y1, x2, y2);
end;
powyższa procedura rysuje kwadrat o podanym kolorze i w określonym obszarze. Aby wykorzystać procedurę Rysuj potrzebny nam będzie przycisk. Wstaw go na formę i w zdarzeniu OnClick wpisz:
rysuj(10, 10, 50, 50, clGreen);
Na formie zostanie narysowany zielony kwadrat. Przykład wydaje się banalny, ale gdyby potrzeba była narysowania 100 takich kwadratów o różnych kolorach i różnych miejscach. A co gdyby procedura miała wykonać operacje mieszczące się w 100 linijkach kodu? Jak widać rozbudowany kod możemy sprowadzić do jednej linijki i wykorzystywać go w każdym miejscu programu.
Podobne do procedur są funkcje. Różnią się tym że deklarujemy jej wynik, tzn. czy ma to być tekst, liczba itp. Najlepiej wyjaśnić to na przykładzie:
function CzyZero(l1, l2: integer) : string;
begin
if l1-l2=0 then Result:='Wynikiem jest zero' else
Result:='Wynikiem nie jest zero';
end;
Teraz wstaw na formę Button i dwa Labele. Pod zdarzenie OnClick przycisku wpisz:
Label1.Caption := CzyZero(10,234);
Label2.Caption := CzyZero(10,10);
Jak widać nasza funkcja działa poprawnie. Zwraca ona wyniku odejmowania tylko odpowiedni tekst. Wynik wykonania funkcji podajemy po słowie Result:=.
Teraz zajmiemy się modułem. Jest to plik, który zawiera procedury i funkcje. Stworzymy moduł, który zawiera powyższe przykłady. Zamknij wszystkie projekty i utwórz nowy unit (File -> New -> Unit).
Skasuj niepotrzebne elementy kodu i dopisz nowe tak aby miał zawartość jak kod poniżej, przyjrzyj się mu:
unit test;
interface
{ informujemy moduł, że korzysta on z grafiki }
uses Graphics; { informujem moduł jakie zawiera funkcje i procedury }
function CzyZero(l1, l2: integer) : string;
procedure Rysuj(can: TCanvas; x1, y1, x2, y2: Integer; kolor: TColor);
implementation
function CzyZero(l1, l2: integer) : string; { nasza funkcja}
begin
if l1-l2=0 then Result:='Wynikiem jest zero' else
Result:='Wynikiem nie jest zero';
end;
{ nasza procedura. Została lekko zmieniona (can: TCanvas). Jako że nie mamy formy, musimy poinformować procedurę na czym ma rysować kwadrat.}
procedure Rysuj(can: TCanvas; x1, y1, x2, y2: Integer; kolor: TColor);
begin
can.Brush.Color:=kolor;
can.Rectangle(x1, y1, x2, y2);
end;
end.
Zapisz go do jakiegoś katalogu (np c:\test) jako "test". Teraz utwórz nową aplikację (File -> New -> Application) i zapisz ją do tego samego folderu . Na formę wstaw Button i Label. Do deklaracji "uses" programu dodaj test. Teraz w zdarzeniu OnClick przycisku wpisz:
rysuj(Form1.Canvas, 10, 10, 50, 50, clMaroon);
Label1.Caption := CzyZero(100, 50);
Jeżeli wszystko wykonałeś prawidłowo to ujrzysz taki sam efekt jak przy wykonaniu procedury Rysuj i funkcji CzyZero w podanych wcześniej przykładach. Jeżeli mamy wiele funkcji i procedur, z których korzystamy w naszym programie możemy utworzyć moduł. Po co? Zauważ, że kod programu staje się bardziej przejrzysty i estetyczny.
WPROWADZENIE DO OBIEKTOWEJ TECHNIKI PROGRAMOWANIA
Programowanie obiektowe polega na operowaniu w programie obiektami, którymi są dane wraz z tak zwanymi metodami, czyli procedurami i funkcjami. Mogą one zostać wykorzystane wyłącznie dla ściśle określonych danych. Obiektami w naszych programach są np. komponenty które umieszczamy na formularzu. Zmienna obiektowa lub po prostu obiekt jest elementem pewnej klasy. Klasa jest to typ obiektowy, który definiujemy w podobny sposób jak typ rekordowy, zastępując słowo kluczowe record słowem kluczowym class. Rozważmy następujący fragment programu:
Type
Tekst20=string[20];
Osoby = class(TObject)
Nazwisko:tekst20;
Imie:tekst20;
adres:tekst20;
ksiazk: integer, {liczba wypożyczonych książek}
end;
Powyższy fragment programu definiuje typ obiektowy o nazwie osoba zawierający następujące pola: nazwisko, imię, adres uraz książki. Dostęp do tych pól oraz wyprowadzanie ich zawartości powinno odbywać się wyłącznie przy wykorzystaniu metod czyli procedur i funkcji. Nagłówki procedur i funkcji powinny być zadeklarowane w definicji klasy, natomiast ich treść podana w dalszym ciągu programu. System Delphi choć akceptuje sposób deklaracji klas przy pomocy słowa object wykorzystywanego w języku turbo pascal, posiada swój własny mechanizm tworzenia obiektów. Konstrukcja:
Osoby=class(TObject)
Oznacza, że klasa osoby jest pochodna klasy Tobject, gdzie klasa TObject jest klasą standardową, od której pochodzą wszystkie inne klasy. Możliwa też jest konstrukcja:
Osoby = class
która jest równoważna poprzedniej.
Przypuśćmy, że dla klasy Osoby chcemy mieć trzy metody: pierwszą o nazwie Init, służącą do wprowadzania danych do pól obiektu, drugą o nazwie Druk wykorzystywaną do wyprowadzenia danych zawartych w polach obiektu oraz trzecią metodę o nazwie Sprawdź umożliwiającą sprawdzenie czy ule została przekroczona liczba -wypożyczonych książek (nazwa Init powinna być zawsze stosowana dla metody inicjującej obiekt). Deklaracja klasy Osoba może zatem zostać rozszerzona w sposób następujący:
type
tekst20 = string[20];
Osoby = class(TObject)
nazwisko:tekst20;
imie:tekst20;
adres:tekst20;
ksiazki:integer;
procedure lnit(aNazwisko, aImie, aAdres :tekst20;aKsiazki:integer);
function Sprawdz: boolean;
procedure Druk;
end;
A oto przykładowa treść metod Init, Sprawdź oraz Drukuj:
procedure Osoby.lnit(aNazwisko, aImie, aAdres:tekst20;aKsiazki:integer);
begin
nazwisko := anazwisko;
imię := aimie;
adres := aAdres;
ksiazki := aKsiazki;
end;
function Osoby. Sprawdz: boolean;
bogin
if książki < 7 then sprawdz := false else
sprawdź := true end;
procedure Osoby.Druk;
bogin
pole.Caption:-nazwisko+' `+imie+' '+adres;
end;
Zwróćmy uwagę, że w instrukcji procedurę przed nazwą metody występuje nazwa klasy wraz z kropką oddzielającą te dwie nazwy. Metoda zdefiniowana w danej klasie może być stosowana wyłącznie do wykonywania operacji na polach określonych w tej klasie. Pola danego obiektu w momencie wykonywania metody są automatycznie dostępne. Daną metodę wywołujemy w ten sposób, że najpierw podajemy nazwę obiektu, a następnie po kropce nazwę metody. Na przykład dla rozważanej klasy Osoby można zadeklarować najpierw dwa obiekty o nazwach x,y, ą następnie przypisać polom tych obiektów pewne wartości. Deklaracje obiektów realizuje się następująco:
x, y: Osoby {zadeklarowanie obiektów klasy Osoby}
W celu przypisania polom obiektu x konkretnych wartości należy wywołać metodę Init w postaci:
x.lnit(`Kowalski', 'Jan',, Warszawa', 5);
co powoduje, ze pola obiektu x: nazwisko, imię, adres, książki przyjmą wartości 'Kowalski', 'Jan', 'Warszawa', 5.
Warto zwrócić uwagę na fakt, że identyfikacja obiektu, dla którego ma być dokonana operacja przypisania, odbywa się poprzez podanie odpowiedniej nazwy w wywołaniu. Jeżeli napiszemy x.Init, to operacja zostanie wykonana dla pól obiektu x, natomiast y.Init powoduje wykonanie operacji dla pól obiektu y. Należy też podkreślić, że metoda Init może być wykorzystana wyłącznie dla obiektów klasy Osoby. Błędne byłoby wywołanie postaci:
lnit('Tomaszewski', 'Piotr', 'Katowice',3);
z bardzo prostego powodu, a mianowicie nie są określone pola, którym należy przypisać wartości. Do wyprowadzenia zawartości pól obiektów klasy Osoby służy metoda Druk wywołana następująco:
x. Druk;
y. Druk;
Najpierw zostaną wyprowadzone zawartości pól obiektu x, a następnie obiektu y.
Podsumujemy teraz zdobyte do tej pory wiadomości o programowaniu obiektowym. Obiekt składa się z pól (analogicznych do pól rekordu) oraz metod operujących na tych polach. Dostęp do tych pól powinien się odbywać wyłącznie przy pomocy metod. Taka własność programowania obiektowego na2ywa się hermetyzacja. Z punktu widzenia dyscypliny programowania jest to bardzo korzystne, w jednym miejscu są bowiem zgromadzone zarówno deklaracje pól jak i deklaracje metod pozwalających przetwarzać dane zawarte w polach. Hermetyzacja pozwala również na automatyczną kontrolę poprawności wywołań procedur i funkcji. W programowaniu obiektowym daną metodę możemy wywołać wyłącznie dla właściwych parametrów, a mianowicie dla pól obiektu, w którym jest ona zadeklarowana. Podstawowa różnica pomiędzy programowaniem tradycyjnym, a obiektowym polega zatem na tym, że w programowaniu tradycyjnym przy wywołaniu procedur są przekazywane im dane, natomiast w programowaniu obiektowym aktywuje się metody dla odpowiednich danych umieszczonych w polach obiektu. W programowaniu nieobiektowym bardzo niebezpieczne jest modyfikowanie istniejących struktur danych. Przy jakiejkolwiek zmianie struktury danych należy sprawdzić w całym programie konsekwencje jej wprowadzenia. W programowaniu obiektowym, zmiana struktury danych ogranicza się do obiektu, którego
dotyczy.
DZIEDZICZENIE
Jedną z własnością programowalna obiektowego jest dziedziczenia
Dziedziczenie polega na tym, że dana klasa (typ obiektowy), może być utworzona niezależnie lub jako potomek wcześniej utworzonej klasy. Klasa utworzona w -wyniku dziedziczenia jest nazywana pochodną danej klasy bazowej. Proces dziedziczenia może być kontynuowany, tzn. klasa pochodna może być klasą bazową dla kolejnej pochodnej. Klasa pochodna dziedziczy po klasie bazowej jej pola i metody. Deklaracja klasy pochodnej przeprowadza się pisząc po sławie kluczowym class umieszczoną w nawiasach nazwę klasy bazowej.
Przykład:
Rozważmy klasę Osoby
Osoby = class(TObject)
nazwisko:tekst20;
imię: tekst20;
adres: tekst20;
książki: integer;
procedure Init(a Nazwisko, almie, aAdres: tekst20; aKsiazki: integer);
function Sprawdz: boolean:
procedure Drukuj;
end;
Od klasy Osoby możemy zdefiniować klasę pochodną Naukowiec, w sposób następujący:
Naukowiec= class(Osoby)
godziny: integer;
procedurę lnit(aNazwisko. aImie, aAdres:tekst20; aKsiazki, aGodziny.integer);
procedure Sprawdz;
procedurę Drukuj;
end;
Klasa Naukowiec posiada pole godziny oraz trzy metody mit. Sprawdź oraz Drukuj. Po klasie bazowej dziedziczy ponadto wszystkie pola oraz wszystkie metody. Zauważmy, że nazwy metod w klasie pochodnej i klasie bazowej są takie same. Nie prowadzi to jednak do kolizji, ponieważ przy wywołaniu metody dla danego obiektu najpierw jest sprawdzane czy dana metoda jest zdefiniowana w klasie w której elementem jest rozpatrywany obiekt, a jeśli nie to są przeszukiwane klasy bazowe. Zjawisko nadawania tych samych nazw metodom w hierarchii klas nazywamy wielopostaciowością. Oczywiście nadawanie tych samych nazw ma sens tylko wtedy, gdy metoda Init dla klasy Osoby wykonuje operację wprowadzania danych i metoda Init dla klasy Naukowiec również wykonuje taką operację, z tym, że dla innych danych. Zauważmy jeszcze, że dla klasy Naukowiec możemy używać metodę Init z tej klasy jak i metodę Init z klasy Osoby, natomiast dla klasy Osoby możemy tylko wykorzystywać metodę Init z tej klasy.
METODY WIRTUALNE
Z właściwości dziedziczenia w programowaniu obiektowym wynika, że pewne klasy w swojej hierarchicznej strukturze mogą posiadać takie same nazwy. Jeżeli metody te posiadają w swojej definicji słowo virtual (umieszczone na końcu), to w momencie wywołania takiej metody z innej kompilator automatycznie rozpozna, którego obiektu dotyczy dane wywołanie. Dla klas, w których definiowane są metody wirtualne, dany obiekt powinien być zainicjowany przy pomocy specjalnej metody-konstruktora, w której słowo kluczowe procedurę jest zastąpione słowem constructor (konstruktor może być również stosowany dla obiektów nie zawierających metod wirtualnych). W celu rozpatrzenia mechanizmu wykorzystywania metod wirtualnych rozważymy następujące programy, pierwszy wykorzystuje metody wirtualne, a drugi nie:
program virtual;
useswincrt;
type
Pierwszy=class nazwa:string;
constructor Init(x: string);
procedure Komunikat;
virtual procedurę Wołaj;
end;
Drugi= class(Pierwszy) ;
procedure Komunikat; virtual;
end;
constructor Pierwszy.Init(x: string);
begin
nazwa:= v, end;
procedurę Pierwszy. Komunikat;
begin
Editl.Text:= 'Komunikat A dla obiektu:'+nazwa;
end;
procedure Pierwszy.Wołaj;
begin
Komunikat end;
procedurę Drugi.Komunikat;
begin
Edit2.Text:= 'Komunikat B dla obiektu:'+nazwa;
end;
var
x: Pierwszy;
y: Drugi;
begin
x.Init('obiekt A');
y.Init('obiektB');
x.Wolaj;
y. Wołaj;
end.
W powyższym programie zdefiniowano dwie klasy, klasę bazową. Pierwszy i klasę pochodną Drugi. W obu klasach występują definicje metody wirtualnej o nazwie Komunikat. Ponieważ zgodnie z metodami dziedziczenia metoda Wołaj jest dostępna również w klasie Drugi, więc w zależności od tego, dla którego obiektu wywołamy metodę Wołaj, zostanie wykonana odpowiednia metoda wirtualna Komunikat: albo zdefiniowana w Klasie Pierwszy albo w klasie Drugi. Wynikiem działania powyższego programu jest:
Komunikat A dla obiektu : obiekt A Komunikat B dla obiektu : obiekt B A zatem instrukcja x.Wolaj; powoduje wykonanie metody Komunikat zdefiniowanej w klasie Pierwszy, a instrukcja y. Wołaj powoduje wykonanie metody Komunikat zdefiniowanej w klasie Drugi. Kompilator automatycznie rozpoznaje, dla którego obiektu jest wykonywana metoda Wołaj i realizuje odpowiednią metodę
program nievirt;
useswincrt;
type
Pierwszy =class nazwa:string;
constructor Init(x: string);
procedure Komunikat;
procedure Wołaj;
end;
Drugi== dass(Pierwszy);
procedurę Komunikat;
end;
procedure Pierwszy. Init(x: string);
begin
nazwa:=' x;
end;
procedure Pierwszy.Komunikat;
begin
Editl.Text:= 'Komunikat A dla obiektu :'+nazwa'; end;
procedure Pierwszy.Wołaj;
begin
Komunikat end;
procedurę Drugi.Komunikat;
begin
Edit2.Text:= 'Komunikat B dla obiektu:'+nazwa end;
var
x: Pierwszy;
y: Drugi;
begin
x.Init('obiekt ");
y.mit('obiektB');
x.Wolaj;
y.Wołaj;
end.
Wyniki działania programu są nasteoujące:
Komunikat A dla obiektu: obiekt A Komunikat A dla obiektu : obiekt B
Dla obu obiektów wykonana jest metoda Komunikat zdefiniowana w klasie Pierwszy.
WŁAŚCIWOŚCI KOMPONENTÓW-PROPERTIES
Komponenty dzielimy na widoczne i nie widoczne. Tych drugich nie widać podczas działania programu, jednakże możemy się do nich odwoływać. Komponenty widoczne posiadają zbiór właściwości, które można zmienić podczas projektowania. Należy dodać fakt, iż gdy piszemy własny komponent możemy stworzyć własną właściwości.
Align
służy do wyśrodkowania komponentu, dostępnych jest sześć możliwości:
alNone - brak wyśrodkowania, komponent przyjmuje zdefiniowane wymiary i położenie
alLeft - wyrównanie do lewej krawędzi formy/panelu
alRight - wyrównanie do prawej krawędzi formy/panelu
alTop - wyrównanie do górnej krawędzi formy/panelu
alBottom - wyrównanie do dolnej krawędzi formy/panelu
alClient - komponent zajmuje całą powierzchnię formy/panelu
Caption i Text
jeżeli kontrolka posiada możliwość wyświetlania tekstu to tu deklarujemy jego treść
Color
tutaj definiujemy kolor komponentu; w liście dostępnej w Object Inspectorze znajdują się podstawowe barwy, większą ich ilość uzyskamy poprzez dwukrotne kliknięcie w polu wyboru
Cursor
każdy komponent może mieć inny kursor; w liście Object Inspectora znajdują się standardowe kursory Windowsa;
Enabled
podajemy informację o tym, czy komponent jest dostępny (TRUE- tak, FALSE- nie); jeżeli mamy np. Button na formie to gdy ustawimy właściwość na FALSE to nie będzie reagować na kliknięcie
Font
jeżeli komponent posiada możliwość wyświetlania tekstu to tu możemy ustalić jego czcionkę; więcej możliwości uzyskuje się poprzez dwukrotne kliknięcie w polu wyboru
Height
definiujemy wysokość komponentu
Width
szerokość komponentu
Hint
gdy ustawisz kursor nad zegarkiem (w pasku zadań) to po chwili wyskoczy okienko z aktualną datą, to jest właśnie Hint (podpowiedź); tutaj deklarujesz jaki tekst ma się wyświetlić po najechaniu kurosrem na dany komponent
ShowHint
tu informujemy komponent, czy ma wyświetlać podpowiedzi (Hint)
Left
położenie komponentu względem osi X
Top
położenie komponentu względem osi Y
Name
nazwa komponentu, każdy komponent musi mieć inną nazwę, jeżeli położysz na formie dwa Labele to zauważysz, że nazywają się Label1 i Label2; nazw używamy, gdy odwołujemy się do komponentu z innego miejsca (np. Label1.Caption:='OK')
Tag
jest to dodatkowa komórka pamięci, w której możemy przechowywać dodatkowe informacje
Visible
deklarujemy czy komponent ma być widoczny, czy też nie
ZDARZENIA KOMPONENTÓW-EVENT
Oprócz właściwości komponenty posiadają także zdarzenia. Służą one do wykonywania czynności, gdy zajdzie określony warunek. Lista najczęściej występujących poniżej.
Click(Sender: TObject);
zwykłe kliknięcie na komponencie; (np. wstawiamy na formę Button i w zdarzeniu OnClick piszemy Form1.Caption:='Click';)
DblClick(Sender: TObject);
to samo co wyżej, lecz akcja zachodzi dopiero po dwukrotnym kliknięciu
KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
jeżeli klawisz został wciśnięty. Key to klawisz który się wcisnął, Shift to klawisz typu Alt, Ctrl lub Shift
type TShiftState = set of (ssShift, ssAlt, ssCtrl, ssLeft, ssRight, ssMiddle, ssDouble);
np. if (Shift=ssAlt) and (Key=VK_RETURN) then wcisnęliśmy Alt+Enter
KeyPress(Sender: TObject; var Key: Char);
zwykłe naciśnięcie klawisza czyli nacisnąć i puścić tutaj mamy Key jako Char czyli od razu wiemy co się nacisnęło i możemy zrobić np. tak Form1.Caption := Form1.Caption + Key;
KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
jeżeli klawisz został zwolniony,parametry takie same jak w KeyDown
end;
MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
jeżeli trzymamy wciścnięty klawisz myszy, podobnie jak z klawiaturą tyle że tu jest myszka, event uruchamiany gdy naciśniemy któryś z przycisków myszki, o czym daje znać Button [mbLeft, mbRight lub mbMiddle] Shift to tak jak w KeyDown [ssAlt lub ssShift], X i Y współrzędne wciśnięcia myszki
MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
jeżeli poruszamy myszką, (najczęściej uruchamiany event), włącza się on gdy ruszamy myszką po komponęcie, X i Y to aktualne położenie kursora myszki na formie, a Shift już chyba jest znany
end;
MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
jeżeli klawisz myszki został zwolniony, gdy zrobiliśmy MouseDown kolej na MouseUp, wszystko tak samo jak w MouseDown
Activate(Sender: TObject); zachodzi kiedy komponent staje się aktywnym
Deactivate(Sender: TObject); kiedy komponent przestaje być aktywny
Destroy(Sender: TObject); a to chwila przed zniszczeniem [zwolnieniem] komponentu
FormClose(Sender: TObject; var Action: TCloseAction);
jeśli jest to główna forma aplikacji to w tym miejscu możemy zwalniać zasoby, event wywoływany gdy dane okno jest zamykane (zamknięcie głównej formy powoduje wyłączenie programu). Action jest to akcja jaką ma wykonać, najbardziej przydatne to:
Action:=caNone; - nie robi nic nawet nie zamyka okienka
Action:=caFree; - zamyka okno i zwalnia
pozostawienie Action bez zmian powoduje zamknięcie okna
FormCloseQuery(Sender: TObject; var CanClose: Boolean); żądanie zamknięcia okienka, CanClose:=True oznacza, że zezwalamy na to
FormCreate(Sender: TObject); wywoływane gdy forma jest tworzona
FormPaint(Sender: TObject); zdarzenie polegające na konieczności odświeżania zwartości formularza, dlatego jeżeli chcemy coś narysować na formularzu to proponuję tutaj.
FormResize(Sender: TObject); gdy formie zmienia się rozmiar
FormShow(Sender: TObject); gdy forma jest pokazywana czyli np. Form1.Show
FormDragDrop(Sender, Source: TObject; X, Y: Integer); kiedy wykonamy Drag (czyli podnieś) a potem Drop (czyli upuść) myszką wtedy ten event zostanie wywołany. Source to obiekt z którego dragowaliśmy, natomiast X, Y to współrzędne wykonania dropa
FormDragOver(Sender, Source: TObject; X, Y: Integer;State: TDragState; var Accept: Boolean);
zachodzi kiedy kiedy zrobiliśmy Drag i wykonujemy Over [przesuwamy to co dragneliśmy myszką]
( Source j.w., X i Y to współrzędne w których właśnie robimy Over), Accept:=True oznacza, że akceptujemy w tym miejscu wykonanie Dropa
Change(Sender: TObject); dostępne dla wielu komponentów, w które można wpisywać dane, wywoływane gdy zawartość się zmienia
Zazwyczaj zdarzenia (venty) są tak dobrze nazywane, że można poznać do czego są, jak działają i kiedy są uruchamiane.
ASCII |
|
|
CANVAS
Zajmiemy się rysowaniem po formularzu czyli grafiką. Metoda, która będzie nam to tego potrzebna nazywa się Canvas i określa obszar rysowania. Metoda ta jest dostępna dla wielu obiektów, nas głownie będzie interesowała dla formularza, ponieważ właśnie po formularzu będziemy rysowali.
Dla metody canvas istniej wiele procedur i funkcji, najlepiej można się o tym przekonać wpisując Canvas. I rozwinie się lista tych metod. Niektóre z nich zostaną omówione.
Narysujemy linie proste, krzywe, figury geometryczne, nauczymy się wypełniać zamknięte obszary.
Na początek linie. Do narysowania linii prostej służą funkcje MoveTo(x,y) i LineTo(x,y). Pierwsza z nich służy do ustalenia pierwszego punktu, a drugi do ustalenia drugiego (końcowego), np.:
MoveTo(0,0);
LineTo(Form1.Width, Form1.Height)
narysuje linię prowadzącą z lewego górnego narożnika formy do jej lewej dolnej krawędzi.
Do wygenerowania punktu może służyć metoda Pixels np.:
Canvas.Pixels[120,240]:=clLime; //wygenerowanie punktu na formularzu w kolorze Lime
Do narysowania figury foremnej służą procedury:
Canvas.Rectlange(X1:integer;Y1:integer;X2:integer;Y2:integer); // rysuje prostokąt o podanych wymiarach
Canvas.Ellipse(X1:integer;Y1:integer;X2:integer;Y2:integer); //rysuje elipsę o podanych wymiarach
Do określenia wypełnienia takiego obiektu służy metoda Brush np.:
Canvas.Brush.Color:=clblue //wypełnienie kolorem niebieskim
Canvas.Brush.Styl:=bsClear //obiekt zostaje wyczyszczony
Podobnie aby określić kontur obiektu należy użyć metody Pen np.”
Canvas.Pen.Color:=clred //kontur zostanie narysowany kolorem czerwonym
Canvas.Pen.Styl:=psDot //obiekt zostaje narysowany linią przerywaną
Teraz narysujemy krzywe. Do ich rysowania służy funkcja PolyBezier(canvas handle, pointer to array of TPoint, number of points). narysujemy dwiema krzywymi ósemkę:
var
pkt:array[1..4] of TPoint; // tablica ze współrzędnymi
begin
pkt[1]:=Point(100,0); // podanie współrzędnych
pkt[2]:=Point(0,50);
pkt[3]:=Point(200,100);
pkt[4]:=Point(100,150);
PolyBezier(canvas.handle, pkt, 4); // narysowanie pierwszej części
pkt[1]:=Point(100,0);// podanie nowych współrzędnych
pkt[2]:=Point(200,50);
pkt[3]:=Point(0,100);
pkt[4]:=Point(100,150);
PolyBezier(canvas.handle, pkt, 4); // narysowanie drugiej części
end;
Do narysowania figur można wykorzystać dwie funkcje: PolyLine(canvas handle, pointer to array of TPoint, number of points) lub Polygon(canvas handle, pointer to array of TPoint, number of points); np.:
Narysujemy w lewym górnym rogu formularza gwiazdę:
var pkt: array[1..6] of TPoint;
begin
pkt[1]:=Point(40,10);
pkt[2]:=Point(20,60);
pkt[3]:=Point(70,30);
pkt[4]:=Point(10,30);
pkt[5]:=Point(60,60);
pkt[6]:=Point(40,10);
Polyline(canvas.handle,pkt,6);
end;
Narysujemy trapez:
var pkt: array[1..4] of TPoint;
begin
pkt[1]:=Point(100,0);
pkt[2]:=Point(0,200);
pkt[3]:=Point(300,200);
pkt[4]:=Point(200,0);
Polygon(canvas.handle, pkt, 4);
end;
Aby wypełnić danym kolorem zamknięty obszar można użyć do tego funkcja FloodFill(X, Y, TColor; TFillStyle).
var
pkt: array[1..4] of TPoint;
begin
pkt[1]:=Point(100,0);
pkt[2]:=Point(0,200);
pkt[3]:=Point(300,200);
pkt[4]:=Point(200,0);
Polygon(canvas.handle, pkt, 4);
canvas.brush.color:=clred;
Canvas.FloodFill(100, 1, clWhite, fsSurface);
end;
Są dwie możliwości wypełnienia: fsSurface - Wypełnia obszar, który zawiera kolor zadeklarowany w funkcji; fsBorder - Wypełnia obszar, który nie zawiera koloru zadeklarowanego w funkcji.
Wszystkie te instrukcje najlepiej umieścić w procedurze:
procedure TForm1.FormPaint(Sender: TObject);
begin
end;
uruchamianej po zajściu zdarzenia OnPaint polegającego na konieczności odświeżania formularza.
Ćwiczenia
Narysuj na formularzu koła olimpijskie każde w innym kolorze.
Narysuj na formularzu dowolną figurę i wpraw ją ruch, tak aby zmieniała swoje miejsce na formularzu.
Umieść na formularzu tekst „Programowanie w Delphi” i wpraw ten tekst w ruch tak aby pojawił się z lewej strony formularza i chował się z prawej strony. Wystarczy jeżeli ruch zostanie wykonany raz.
Narysuj na formularzu choinkę i gwiazdkę oraz dołóż kolędę, która będzie uruchamiana po kompilacji programu.
Wykonaj w delphi formularz w którym zademonstrujesz możliwości rysowania na formularzu różnych figur.
CDPLAYER
Pewnie większość z Was chciałaby napisać sobie prosty odtwarzacz płyt CD. Otóż w systemie Delphi można odtwarzać dźwięk Audio CD za pomocą komponentu TMediaPlayer, który znajduje się na zakładce System.
Odtwarzanie dźwięku za pomocą tego komponentu jest względnie proste. Wystarczy zmienić wartość właściwości DeviceType na dtCDAudio.
Najtrudniejszym do zrozumienia aspektem programowania urządzeń Audio CD są różne formaty czasu. Do zebrania informacji o danej ścieżce lub ustawienia bieżącej pozycji na określonej ścieżce należy skorzystać z czasu w formacie TMSF ( ścieżka-minuty-sekundy-ramki ). Wartości minut, sekund lub ramek będą ustawiane względem numeru ścieżki. Poniższy przykładowy kod formatuje łańcuch informujący o bieżącej pozycji wewnątrz bieżącej ścieżki:
var
Czas : Integer;
Piosenka : Integer;
Minuty : Integer;
Sekundy : Integer;
CzasStr : string;
begin
MediaPlayer1.TimeFormat := tfTMSF;
Czas := MediaPlayer1.Position;
Piosenka := mci_TMSF_Track(Czas);
Minuty := mci_TMSF_Minute(Czas);
Sekundy := mci_TMSF_Second(Czas);
CzasStr := Format('Czas piosenki: %2.2d:%2.2d', [Minuty.Sekundy]);
Label1.Caption := 'Piosenka: ' +IntToStr(Piosenka);
Label2.Caption := CzasStr;
end;
Na początku właściwość TimeFormat jest ustawiona na tfTMSF, następnie bieżąca pozycja jest zapisywana w zmiennej Czas. W kolejnych liniach kodu makropolecenia konwersji czasu ( należące do Windows ) - mci_TMSF_Track, mci_TMSF_Minute, mci_TMSF_Second - wydobywają z tej zmiennej różne wartości czasowe ( nr ścieżki, minuty, sekundy ). Makra te są zawarte w module MMSystem, dlatego, aby móc z nich skorzystać, trzeba dodać nazwę tego modułu do listy uses. Po wyodrębnieniu indywidualnych jednostek budowany jest łańcuch, który posłuży do wyświetlnia czasu ścieżki. Na samym końcu ścieżka i czas zostają wyświetlone przez 2 komponenty typu Label.
Do zebrania ogólnej informacji o płycie CD służy czas w formacie MSF ( minuty, sekundy, ramki ). Format ten może służyć do określenia bieżącej pozycji na płycie względem jej początku lub do ustawienia bieżącej pozycji np. na 30. minucie płyty niezależnie od tego, na której ścieżce wypadnie to miejsce. Poniższy przykład pokazuje w jaki sposób uzyskać i wyświetlić bieżącą pozycje na płycie ( liczoną w minutach i sekundach ):
var
Czas : Integer;
Minuty : Integer;
Sekundy : Integer;
CzasStr : string;
begin
MediaPlayer1.TimeFormat := tfMSF;
Czas := MediaPlayer1.Position;
Minuty := mci_MSF_Minute(Czas);
Sekundy := mci_MSF_Second(Czas);
CzasStr := Format('Całkowity czas płyty: %2.2d:%2.2d', [Minuty, Sekundy]);
Label3.Caption := CzasStr;
end;
DATA I CZAS
Gdy piszemy aplikację często chcemy by wyświetlała aktualną datę i godzinę. Istnieje kilka sposobów.
Najprostszy sposób (13:48:04, 02-12-22):
Label1.Caption:=TimeToStr(Time)+#13+DateToStr(Date);
Czasochłonny sposób (14:3:23, 31-3-2002):
var
rok,miesiac,dzien,godziny,minuty,sekundy,msekundy:word;
begin
decodedate(now,rok,miesiac,dzien);
decodetime(now,godziny,minuty,sekundy,msekundy);
Label1.Caption:=IntToStr(godziny)+':'+IntToStr(minuty)+':'+IntToStr(sekundy)+#13+ IntToStr(dzien)+'-'+IntToStr(miesiac)+'-'+IntToStr(rok);
end;
Sposób dający najwięcej możliwości:
Label1.Caption:=
FormatDateTime('dd mmmm yyyy', Now)+#13+ // 31 marzec 2002
FormatDateTime('dd mm yy', Now)+#13+ // 31 03 02
FormatDateTime('dd mm yyyy', Now)+#13+ // 31 03 2002
FormatDateTime('ddd dd mmmm yyyy', Now)+#13+ // N 31 marzec 2002
FormatDateTime('dddd dd mmmm yyyy', Now)+#13+ // niedziela 31 marzec 2002
FormatDateTime('dddd dd mm yyyy', Now)+#13+ // niedziela 31 03 2002
FormatDateTime('dddd', Now)+#13+ // niedziela
FormatDateTime('mmmm', Now)+#13+ // marzec
FormatDateTime('hh mm ss', Now); // 14 26 20
end;
Dzień tygodnia można uzyskać także w inny sposób:
var
Data: TDateTime;
dni: array[1..7] of string;
begin
dni[1] := 'Niedziela';
dni[2] := 'Poniedziałek';
dni[3] := 'Wtorek';
dni[4] := 'Środa';
dni[5] := 'Czwartek';
dni[6] := 'Piątek';
dni[7] := 'Sobota';
Data:=Date;
Label1.Caption:=dni[DayOfWeek(Data)];
end;
Sprawdzenie, czy rok jest przestępny. Rok jest przestępny gdy dzieli się przez 4 i (nie jest podzielny przez 100 lub jest podzielny przez 400) :)
function Przestepny(Rok: Integer): Boolean;
begin
Result := (Rok mod 4 = 0) and ((Rok mod 100 <> 0) or (Rok mod 400 =0));
end;
wykorzystanie:
if Przestepny(rok) then label1.caption:='Tak' else Label1.caption:='Nie'; // (rok) - np. 2000
A na koniec sprawdzimy ile dni i godzin minęło pomiędzy dwiema datami:
var
D1,D2:TDateTime;
begin
D1 := StrToDate('02-04-30'); // rok, miesiąc, dzień
D2 := StrToDate('02-04-1');
ShowMessage('Dni= '+FloatToStr(D1-D2)+' Godziny= '+FloatToStr((D1-D2)*24));
DIALOGI
Dialogi w Delphi należą do komponentów strony Dialogs. Są to komponenty niewidoczne ale niezbędne do naszych programów. Zastosowanie tych komponentów może być różnorakie, np. używając jakiś program (chociażby Notatnik) zapewne zauważyłeś, że po kliknięciu w przycisk 'Zapisz' pojawia się okno, w którym podajemy nazwę pliku i folder do którego chcemy zapisać naszą pracę, jest to tzw. okno dialogowe. W Delphi wszystkie okna dialogowe wywołuje się funkcją 'Execute' (np. OpenDialog1.Execute).
Ikona |
Nazwa komponentu |
Nazwa oryginalna |
|
Dialog otwarcia Dialog otwarcia rysunku |
OpenDialog OpenPictureDialog |
|
Dialog zapamiętania Dialog zapamiętania rysunku |
SaveDialog SavePictureDialog |
|
Dialog czcionki |
FontDialog |
|
Dialog koloru |
ColorDialog |
|
Dialog wydruku |
PrintDialog |
|
Dialog ustawień wydruku |
PrintSetupDialog |
|
Dialog znajdowania |
FindDialog |
|
Dialog zastępownia |
ReplaceDialog |
OpenDialog
Open Dialog służy do otwierania plików ( oprócz graficznych ). Poprzez ten komponent jest otwierane okno "Otwórz", w którym można dokonać wyboru pliku.
Przykład 1:
Komponent OpenDialog umożliwia wyświetlenie w polu tekstowym Label1 nazwy wskazanego pliku
OpenDialog1.Execute;
Label1.Caption:=OpenDialog1.Filename;
Przykład 2:
Dzięki OpenDialog możemy załadować np. plik tekstowy do komponentu tekstowego np. Memo,
W Public musisz napisać procedure Open(const AFileName: string);
Natomiast w Implementation :
procedure TForm1.Open(const AFileName: string);
begin
PathName := AFileName;
Caption := ExtractFileName(AFileName);
with memo1 do
begin
Lines.LoadFromFile(PathName);
end;
end;
Oczywiście dialog musi być wywoływany po naciśnięciu dowolnego przycisku:
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
Open(OpenDialog1.FileName);
end;
Przykład 3:
Drugi sposób na to aby załadować plik tekstowy do komponentu Memo, dużo bardziej uprostrzony
if OpenDialog1.Execute then
Memo1.Lines.LoadFromFile(OpenDialog1.Filename);
Efektem tego będzie wywołanie okna dialogowego "Otwórz" i możliwość wybrania pliku tekstowego po czym znajdzie się on w naszym polu tekstowym memo.
W Object ins. możemy ustawić właściwości filtrów które mają być widoczne podczas wywołania okna "Otwórz". Możemy również zmienić we właściwościach filter name nazwę która ma być już wpisana do okienka w którym wybiera się plik, np.:
Filter name |
Filter |
TextFiles |
*.txt |
AnyFiles |
*.* |
W title możemy zmienić dowolną nazwę jaka ma być w lewym górnym rogu okna dialogowego.
SaveDialog
Jest to okno podobne do OpenDialog, z tym że służy do zapisu pliku. Save Dialog służy do zapisywania informacji (przeważnie tekstu) na dysk. Ma on głównie zastosowanie do opcji "Zapisz" oraz "Zapisz jako..". Różnica między nimi jest taka, że "Zapisz jako.." zapisuje tekst do nowego pliku gdzie możesz podać nazwę. Natomiast "Zapisz" polega na dopisywaniu nowych informacji do otwartego pliku w naszym programie.
Przykład 1:
Przykład zastosowania tego dialogu do programu:
1. W Public napisz Zmienna:string;.
2. Natomiast po Form1:TForm1; napisz :
const Dowolnytekst = 'Mój program';
3. Na swojej formie postaw 2 buttony (nazwij je Zapisz i Zapisz jako..).
4.Kliknij podwójnie na Zapisz i wpisz tekst:
SaveDialog1.FileName := Zmienna;
if SaveDialog1.Execute then
begin
Zmienna := SaveDialog1.FileName;
Caption := ExtractFileName(Zmienna);
ZapiszjakoClick(Sender);
end;
5. Kliknij podwójnie na Zapisz jako i wpisz:
if Zmienna = Dowolny tekst then
zapiszclick(Sender)
else
begin
memo1.Lines.SaveToFile(PathName);
memo1.modified:=false;
end;
6. Kliknij podwójnie na formie i wpisz do procedury Form Create:
Zmienna := Dowolny tekst;
OpenPictureDialog, SavePictureDialog
Okno podobne do OpenDialog i SaveDialog, ale służące do otwierania i zapisywania plików graficznych, posiada funkcję podglądu pliku.
Przykład 1:
Otwarcie pliku graficznego w komponencie Image
if OpenPictureDialog1.Execute then
Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
Przykład 2:
Przykład do wywołania okna zapisz jako.. z możliwością szybkiego podglądu plików graficznych (w tym przypadku BMP).
..........
SavePictureDialog1.DefaultExt := GraphicExtension(TBitmap);
SavePictureDialog1.Filter := GraphicFilter(TBitmap);
if SavePictureDialog1.Execute then
End;
..........
FontDialog
Okno pozwalające na zdefiniowanie czcionki (jej rozmiaru, koloru itp.). Dzięki niemu czcionka może być pogrubiona, pochylona, podkreślona itp. Ten komponent znalazł zastosowanie w edytorach tekstowych. Oto kilka przykładów z zastosowaniem FontDialog:
Przykład 1:
Zmiana czcionki na polu tekstowym Label1.
if FontDialog1.Execute then
Label1.Font:=FontDialog1.Font;
Przykład 2
Aby wywołać standardowe okno wyboru rodzaju oraz wielkości i koloru czcionki należy wpisać następujący tekst:
..........
FontDialog1.Font.Assign(Editor.SelAttributes);
if FontDialog1.Execute then
CurrText.Assign(FontDialog1.Font);
SelectionChange(Self);
memo1.SetFocus;
..........
ColorDialog
Okno służące do wyboru koloru.
Przykład 1:
Zmiana koloru formularza
if ColorDialog1.Execute then
Form1.Color:=ColorDialog1.Color;
PrintDialog
Okno służące do wyboru drukarki, zakresu stron, oraz rozpoczęcia drukowania
PrintDialog jest to dialog odpowiedzialny za drukowanie tekstu lub obrazków graficznych. W przypadku tekstu jego zastosowanie jest prostsze w komponencie RichEdit niż w Memo. Kilka poniższych przykładów powinno wam pozwolić zrozumieć działanie tego komponentu.
Przykład 1
Przykład ten jest przykładem drukowania tekstu dla komponentu RichEdit:
1. W private należy napisać zmienna:string;
2. Po przycisku natomiast:
if PrintDialog1.Execute then
Edit1.Print(zmienna);
Przykład 2
Kolejny przykład jest przykładem do drukowania tekstu dla komponentu Memo:
1.Zadeklaruj moduł Printer ( w którym znajduje się metoda AssignPrn)
2. Po przycisku wpisz:
var
Line: Integer;
PrintText: TextFile;
{declares a file variable} begin
if PrintDialog1.Execute then
begin
AssignPrn(PrintText);
Rewrite(PrintText);
Printer.Canvas.Font := Memo1.Font;
for Line := 0 to Memo1.Lines.Count - 1 do
Writeln(PrintText, Memo1.Lines[Line]);
CloseFile(PrintText);
end;
PrinterSetupDialog
Okno służące do zmiany ustawień drukarki (rozmiar papieru, orientacja wydruku itp.)
Przykład 1
Otwarcie okna wysterowania wydruku:
PrinterSetupDialog1.Execute;
FindDialog
Okno szukania tekstu, funkcja szukania jest opisana poniżej
ReplaceDialog
Okno zastępowania tekstu, funkcja zastępowania jest opisana poniżej.
Komponent FindDialog posiada jedno zdarzenie, na które reaguje, zdarzenie OnFind, powstające gdy użytkownik naciśnie klawisz myszki na przycisku Find, w okienku dialogowym. Metoda ta wykonywana po powstaniu tego zdarzenia to Find.DialoglFind. Komponent ReplaceDialog posiada dwa zdarzenia OnFind oraz OnReplace. Zdarzenie OnFind powstaje w tym samym przypadku jak dla komponentu Finddialog, natomiast zdarzenie OnReplace powstaje gdy użytkownik naciśnie na przycisku Replace. Metoda wykonywana po powstaniu zdarzenia OnFind to ReplaceDialog l Find, a metoda wykonywana po powstaniu zdarzenia OnReplace to ReplaceDialog l Replace.
Zastosowanie metody FindDialog l Find oraz RelpaceDialoglFind do znajdowania szukanego tekstu i po znalezieniu podświetlania go w polu edycyjnym Edit, które nazwiemy wzór. Dodatkowo należy w części private zadeklarować zmienną typu logicznego (boolean) wykorzystywaną w metodach komponentu ReplaceDialog.
procedure TForm1.FindDialog1Find(Sender: TObject);
var pozycja: integer; {pozycja wyszukiwanego tekstu}
szukany: string; {wyszukiwany tekst}
tekst: string; {tekst w którym wyszukujemy}
dlugosc: integer; {długość wyszukiwanego tekstu}
begin
szukany := FindDialog1.FindText; {własność FindText podaje tekst do wyszukania}
dlugosc := Length(szukany);
tekst := Wzor.Text; {określenie tekstu w którym wyszukujemy}
pozycja := Pos(szukany, tekst); {funkcja Pos podaje pozycję tekstu szukany w tekście tekst}
if pozycja > 0 then {jeśli znaleziono}
begin
Form1.BringToFront; {odsłonięcie całego formularza}
Form1.ActiveControl := Wzor; {pole wzor jest aktywne}
Wzor.SelStart:= pozycja -1; {własność SelStart podaje początek zaznaczonego tekstu}
Wzor.SelLength := dlugosc; {własność SelLenght podaje długość zaznaczonego tekstu}
end else
MessageDlg('Nie znaleziono', mtInformation, [mbOK], 0);
end;
procedure TForm1.ReplaceDialog1Find(Sender: TObject);
var pozycja: integer;
szukany: string;
tekst: string;
dlugosc: integer;
begin
znajdowano := true; {zapamietanie faktu znajdowania tekstu}
szukany := ReplaceDialog1.FindText; {własność FindText podaje tekst do wyszukania i zastapienia}
dlugosc := Length(szukany);
tekst := Wzor.Text;
pozycja := Pos(szukany, tekst);
if pozycja > 0 then
begin
Form1.BringToFront; {odsłonięcie całego formularza}
Form1.ActiveControl := Wzor; {pole wzor jest aktywne}
Wzor.SelStart:= pozycja -1; {własność SelStart podaje początek zaznaczonego tekstu}
Wzor.SelLength := dlugosc; {własność SelLenght podaje długość zaznaczonego tekstu}
end else
MessageDlg('Nie znaleziono', mtInformation, [mbOK], 0);
end;
procedure TForm1.ReplaceDialog1Replace(Sender: TObject);
begin
if znajdowano = False then {nie znajdowano tekstu}
begin
ReplaceDialog1Find(Sender); {znalezienie tekstu}
Wzor.SelText := ReplaceDialog1.ReplaceText; {zastąpienie znalezionego tekstu podanym tekstem, własność Seltext określa zaznaczony tekst, a własność ReplaceText definiuje wstawiany tekst}
end else
begin {tekst był znajdowany}
Form1.BringToFront; {uwidocznienie formularza}
Wzor.SelText := ReplaceDialog1.ReplaceText; {zastąpienie znalezionego tekstu podanym tekstem}
end;
end;
Objaśnienie
Deklarujemy zmienną tab, która jest tablicą mogącą przechowywać 10 liczb całkowitych. Oczywiście możemy zadeklarować tablicę mogącą przechowywać mniej lub więcej danych. Następnie wypełniamy każdy element tablicy liczbami. Na koniec wyświetlamy na komponencie Label1 wartość czwartej komórki naszej tabeli.
Przykład tablicy dwuwymiarowej:
Objaśnienie
Deklarujemy zmienną tab, podobnie jak w poprzednim przykładzie. Zapewne zauważyłeś że zawartość kwadratowego nawiasu trochę się różni od tego w tablicy jednowymiarowej. Jak sama nazwa mówi mamy dwa wymiary czyli oś x (w poziomie) i y (w pionie). Inaczej też odwołujemy się do zawartości danej komórki takiej tablicy, musimy podać pozycję komórki y i x.