Podstawy Informatyki Wykład XVII Object Pascal Komponenty

background image

Wykład XVII

Object Pascal – Tworzenie

komponentów

Łatwość tworzenia nowych
komponentów i ich adaptacji jest
jednym z największych atutów Delphi.

Podstawy informatyki
Semestr II Transport

background image

Kiedy tworzenie nowego

komponentu jest

uzasadnione ?

jeżeli zastosowanie tworzonego komponentu nie

ograniczy się do jednej aplikacji to praca włożona w jego

tworzenie zwraca się wielokrotnie
stworzenie nowych komponentów może przyczynić się do

bardziej przejrzystego i przyjaznego dla użytkownika

sposobu aplikacji, gdyż logiczny podział jej funkcji (z

punktu widzenia użytkownika) znajdzie odzwierciedlenie

w strukturze użytych komponentów
dla nietypowych zastosowań, gdy brak w środowisku

odpowiednich komponentów – stworzenie ich staje się

warunkiem koniecznym dla stworzenia aplikacji
sprzedaż uniwersalnych komponentów innym

projektantom aplikacji
może stanowić wyzwanie dla projektanta, być

sprawdzianem jego umiejętności

background image

Etapy tworzenia nowego

komponentu

Szczegółowe określenie funkcji komponentu
Zaprojektowanie algorytmu działania komponentu
Sprecyzowanie oraz hierarchiczne i chronologiczne
uporządkowanie poszczególnych czynności
projektowych
Tworzenie komponentu (kodowanie) – powinno
odzwierciedlać logikę komponentu
Testowanie komponentu w ramach projektów
testowych
Zainstalowanie komponentu na palecie
komponentów

background image

Programowe etapy tworzenia

komponentów

Wybór klasy bazowej
Stworzenie modułu źródłowego komponentu
Uzupełnienie definicji dziedziczonych z klasy
bazowej o charakterystyczne dla nowego
właściwości, metody i zdarzenia
Testowanie komponentu
Rejestracja komponentu w środowisku
programistycznym
Stworzenie plików pomocy opisującego
działanie i sposób korzystania z komponentu

background image

Wybór klasy bazowej

Właściwy wybór klasy bazowej ma

decydujący wpływ na postać finalnego

komponentu i wymagany do jego powstania

nakład pracy.
Należy starać się dobrać klasę bazową tak,

by w jak największym stopniu wykorzystać

istniejące właściwości i metody.
Nie ma gotowej recepty na właściwy wybór

jest od wynikiem wiedzy, umiejętności i

doświadczenia programisty, czasem może

być nawet polem eksperymentów.

background image

Tworzenie modułu

źródłowego

Nieodłącznym elementem każdego komponentu jest jego definicja w

kodzie źródłowym, domyślnie każdemu komponentowi odpowiada

oddzielny moduł źródłowy (unit). Definiowanie nowego komponentu

rozpoczyna się od wybrania opcji File|New|Component

wyświetlenia eksperta komponentów. Umożliwia on wybór klasy

bazowej, określenie nazwy tworzonej klasy i jego modułu źródłowego,

wybór strony na palecie komponentów na której komponent zostanie

umieszczony. W rezultacie powstanie jedynie szkielet modułu

zawierający definicję klasy i procedurę rejestracyjną.

Delph

i 4

Delph

i 2

background image

Definiowanie właściwości

prostych

TPrzykladowaKlasa=class(TCustomControl)

private
FIntegerProp: Interer;
FStringProp: String;
FCharProp: Char;
published
property IntererProp read FIntegerProp write

FIntegerProp;
property StringProp read FStringProp write

FStringProp;
property CharProp read FCharProp write FCharProp;

end;

Właściwości reprezentują liczby, wartości lub znaki

background image

Definiowanie właściwości

wyliczeniowych

TPoryRoku=(prWiosna,prLato,prJesien,prZima);

TPrzykladowaKlasa=class(TCustomControl)
private

{pola wewnętrzne}

FPoryRoku: TPoryRoku;

FBooleanProp: Boolean;

published

{właściwości wyliczeniowe}

property PoryRoku read FPoryRoku write FPoryRoku;

property BooleanProp read FBooleanProp write

FBooleanProp;
end;
Wymaga zwykle uprzedniego zdefiniowania typu

wyliczeniowego, edycja w Object Inspectorze

pozwala wybierać wartość właściwości z listy

background image

Definiowanie właściwości zbiorowych

TDni=(Poniedziałek,Wtorek,Środa,Czwartek,Piątek,Sobota,Nie

dziela);
TSetDni=Set of TDni;

TPrzykladowaKlasa=class(TCustomControl)
private

{pola wewnętrzne}

FDyzury: TSetDni;

published

{właściwości wyliczeniowe}

property Dyzury read FDyzury write FDyzury;
end;

Należy zdefiniować bazowy typ wyliczeniowy i oparty na nim

typ zbiorowy, a następnie można zdefiniować odpowiednią

właściwość zbiorową.

background image

Definiowanie właściwości

obiektowych

Nic nie stoi na przeszkodzie,
by właściwością klasy, była
sama klasą lub komponentem.
Za przykład można podać
właściwość Font.

Definicja obiektu, który ma być właściwością innej
klasy powinna (bezpośrednio lub pośrednio)
wywodzić się z klasy TPersistent. Kreowanie
egzemplarza obiektu zawierającego właściwości
obiektowe musi tworzyć obiekt związany z
właściwością obiektową.Podobnie należy
postępować podczas niszczenia obiektu – należy
niszczyć obiekty podrzędne przed zniszczeniem
obiektu nadrzędnego. Konieczne jest zatem
przedefiniowanie konstruktora i destruktora.

background image

Przykładowy obiekt

podrzędny

TJakisObiekt=class(TPersistent)

private
FProp1: Integer;
FProp2: String;
published
property Prop1: Integer read FProp1 write
FProp1;
property Prop2: String read FProp2 write
FProp2;
end;

background image

Przykład definiowania

właściwości obiektowych

TObiektNadrzedny=class(TCustomControl)
private
FJakisObiekt: TJakisObiekt;
procedure SetJakisObiekt(Value: TJakisObiekt);
public
constructor Create(AOwner: TComponent);override;
destructor Destroy;override;
published
property JakisObiekt: TJakisObiekt read FJakisObiekt

write SetJakisObiekt;

end;

background image

Tworzenie obiektów

wewnętrznych

obiekt podrzędny tworzymy w konstruktorze
po utworzeniu obiektu rodzica

constructor TObiektNadrzedny.Create(AOwner:

TComponent);

begin
inherited Create(Aowner);
FJakisObiekt:=TJakisObiekt.Create;
end;

background image

Zwalnianie obiektów

wewnętrznych

obiekt dziecko niszczymy przed zwolnieniem
obiektu nadrzędnego w destruktorze

destructor TObiektNadrzedny.Destroy;
begin
FJakisObiekt.Destroy;
inherited Destroy;
end;

background image

Przypisanie wartości

własności obiektowej

Należy sprawdzić czy przypisany jest jakiś
egzemplarz obiektu. Jeśli tak należy go zwolnić i
dopiero wówczas przypisać nową wartość
właściwości obiektowej

procedure TObiektNadrzedny.SetJakisObiekt(Value:

TJakisObiekt);

begin
if Assigned(FJakisObiekt) then FJakisObiekt.Free;
if Assigned(Value) then FJakisObiekt.Assign(Value)
end;

background image

Redefinicja metody

Assign

Należy tu powiedzieć, że należałoby przedefiniować

metodę Assign obiektu dziecka tak aby obsługiwała

nowe właściwości obiektu

procedure TJakisObiekt.Assign(Source: TPersistant);
begin

if Source is TJakisObiekt then
begin
FProp1:=TJakisObiekt(Source).Prop1;
FProp2:=TJakisObiekt(Source).Prop2;
inherited Assign(Source);
end;

end;

background image

Definiowanie właściwości

tablicowych

Jeśli chcielibyśmy je umieścić w Object

Inspektorze to należy zdefiniować specjalny

edytor właściwości
Właściwość tablicowa musi posiadać jeden lub

więcej indeksów (mogą być one dowolnego

typu)
Klauzule read i write w definicji właściwości

muszą określać metody dostępowe – nie jest

dozwolone specyfikowanie pól
Liczba i kolejność indeksów w odwołaniu do

właściwości być zgodna z jej deklaracją

background image

Przykład typu z

właściwościami

tablicowymi

TPlanety=class(TComponent)
private
function GetPlanetName(const AIndex: Integer): String;
function GetPlanetPosition(const APlanetName: String):

Integer;

public
property PlanetName[const AIndex: Integer]: String

read GetPlanetName; default;

property PlanetPosition[const APlanetName: String]:

Integer
read GetPlanetPosition;

end;

background image

Właściwości tablicowe -

Metody dostępowe

-

Przykład

function TPlanety.GetPlanetName

(const AIndex: Integer): String;

begin
if (AIndex<=0) or (AIndex>9) then
raise Exception.Create(‘Niepoprawny

numer planety. ‘+
’Wprowadź liczbę od 1 do 9’)

else Result::=PlanetNames[AIndex];
end;

background image

Właściwości tablicowe -

Metody dostępowe –

Przykład

cd.

function TPlanety.GetPlanet Position

(const APlanetName: String): Integer;

var I: Integer;
begin
Result:=0; i:=0;
repeat
inc(i);
until (i>9) or

(ANSICompareStr(ANSIUpperCase(APlanetName),

ANSIUpperCase(PlanetNames[i]))=0);

if i<=9 then Result:=i;
end;

background image

Metody dostępowe -

zmiana wartości właściwości

TJakisObiekt=class(TComponent)
{...} FWlasnosc:Integer;
procedure SetWlasnosc(Value: Integer);
{...}
property Wlasnosc: Integer read FWlasnosc write

SetWlasnosc;

{...}
procedure TJakisObiekt.SetWlasnosc(Value: Integer);
begin {...}
Wlasnosc:=Value;

{tu nieskończona rekursja – błąd – winno być np.

FWlasnosc:=Value}

{...}

end;

background image

Zdarzenia

Zdarzenie jest wynikiem oddziaływania użytkownika, ,
systemu operacyjnego, bądź samej aplikacji
Reakcją obiektu na wystąpienie zdarzenia jest
wywołanie związanej z nim procedury zdarzeniowej
(event handler);
Każdemu zdarzeniu, na które zdolny jest reagować
obiekt danej klasy, odpowiada określona właściwość
zdarzeniowa (event property). Zapewnia ona dostęp
do pola, będącego wskaźnikiem do określonej
procedury zdarzeniowej.

background image

Definiowanie zdarzeń

TJakasKontrolka=class(TComponent);
private
FOnClick: TNotifyEvent;
protected
procedure Click; dynamic;
property OnClick: TNotifyEvent read FOnClick write

FOnClick;

end;

Procedury zdarzeniowe w zależności od zdarzenia mają

na ogół różny zestaw parametrów. Typ TNotifyEvent

jest zdefiniowany następująco:

TNotifyEvent=procedure(Sender: TObject) of object

background image

Procedura zdarzeniowa

procedure TJakasKontorlka.Click;
begin
if Assigned(FOnClick) then

FOnClick(Self);

end;

procedura sprawdza czy z obsługą

zdarzenia powiązano jakąś procedurę

(Assigned) i jeśli tak wywołuje ją.

background image

Definiowanie metod

Podczas dodawania i przedefiniowywania metod
komponentów posługujemy się schematem przyjętym
dla klas Object Pascala.
Staramy się unikać wzajemnych powiązań między
metodami (unikać wymogu stosowania metody w
towarzystwie innych metod lub co gorsza, w określonej
sekwencji).
Żadna metoda nie powinna wprowadzać obiektu w stan,
w którym pewne zdarzenia lub właściwości nie są
właściwie obsługiwane.
Należy nadawać metodom nazwy sugerujące
wykonywane przez nie akcje
Właściwie dobieramy stopień widoczności metody

background image

Przedefiniowywanie

konstruktorów

wymaga użycia klauzuli override;

constructor Create(AOwner: TComponent);override;

regułą powinno być również wywołanie konstruktora

klasy macierzystej (bazowej). Przedefiniowywany

konstruktor w klasie pochodnej musi mieć taką samą

strukturę parametryczną jak konstruktor oryginalny.

Klasa może mieć jednak kilka konstruktorów.

constructor TMojKomp.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
{...}
end;

background image

Przedefiniowywanie

destruktorów

wymaga również użycia klauzuli override;

destructor Destroy; override;

wewnątrz destruktora wywołanie destruktora klasy

bazowej jest obowiązkowe i powinno być wykonane

jako czynność ostatnia, np.

destructor TMojKomp.Destroy;
begin
FTimer.Free;
MyString.Free;
inherited Destroy;
end;

background image

Zachowanie się

komponentu na etapie

budowania aplikacji

Konstruktor Create(...) komponentu
wywoływany jest nie tylko w czasie wykonywania
programu, lecz również w momencie wstawiania
go do formularza na etapie budowy aplikacji.
Wynika stąd czasem konieczność rozróżnienia
tych dwu etapów. Rozróżnienie jest możliwe
dzięki właściwości zbiorowej ComponentState.
Poszczególne elementy i ich znaczenie
przedstawia tabela

background image

Znaczenie flag właściwości

ComponentState

csAncesto
r

komponent został odziedziczony z formularza
nadrzędnego

csDesigni
ng

aplikacja znajduje się na etapie projektowania

csFixups

do komponentu istnieje odwołanie z formularza,
który nie jest aktualnie załadowany; po
załadowaniu wszystkich formularzy flaga jest

wyłączana

csLoading odczytywanie danych komponentu ze strumienia
csReading flaga jest ustawiana w momencie utworzenia

komponentu (w wyniku odczytu ze strumienia) i
kasowania wówczas, gdy dany komponent oraz
wszystkie komponenty, od których jest on
zależny, mają już ustalone parametry

csUpdatin
g

komponent jest uaktualniany ze względu na
zmianę definicji z formularzu nadrzędnym

csWriting

trwa zapis komponentu do strumienia

background image

Rejestracja komponentu

Rejestracja komponentu jest czynnością, powodującą
umieszczenie go na Palecie komponentów. Wykonuje ją
procedura o nazwie RegisterComponents():

procedure RegisterComponents(const Page: string;

ComponentClasses: array of TComponentClass);
Pierwszy parametr oznacza nazwę palety komponentów
Drugi zawiera nazwy klas rejestrowanych komponentów
Powyższa procedura musi być wywołana w treści
procedury o nazwie Register, zadeklarowanej także w
części publicznej modułu

background image

Przykład rejestrowania

komponentów

unit MojComp;
interface
type
TMojKomp=class(TComponent)

{...} end;

TInnyKomp=class(Tcomponent) {...} end;

procedure Register;
implementation{...}
procedure Register;
begin
RegisterComponents(‘MojeKomponenty’,[TMojKomp,

TInnyKomp]);

end;
end.

background image

Testowanie

komponentu

Najczęstszym sposobem testowania
komponentu jest stworzenie projektu w
ramach którego obiekt będzie dynamicznie
tworzony i zwalniany.
Projekt ten powinien również pozwalać na
sprawdzenie wszystkich funkcji komponentu.
Należy pamiętać, że dobrze wykonany
komponent powinien być gotowy do
normalnego funkcjonowania już po
wykonaniu konstruktora.

background image

Wybór ikony

komponentu

Komponent nie będzie kompletny, dopóki nie

zostanie opatrzony ikoną identyfikującą go w

palecie komponentów. Do tworzenia ikon można

wykorzystać Image Editor lub dowolny inny

edytor obsługujący pliki BMP.
Ikona musi mieć rozmiary 24x24 i musi być

przechowywana w pliku o takiej samej nazwie jak

nazwa modułu z komponentem i znajdować się w

tym samym co komponent katalogu.
Format pliku jest pod względem struktury

powinien być zgodny z plikami zasobów Windows

(.RES) lecz powinien mieć rozszerzenie .DCR.


Document Outline


Wyszukiwarka

Podobne podstrony:
Sem II Transport, Podstawy Informatyki Wykład XXI Object Pascal Komponenty
Sem II Transport, Podstawy Informatyki Wykład XXI Object Pascal Komponenty
Podstawy Informatyki Wykład XI Object Pascal Podstawy programowania w Object Pascalu
Podstawy Informatyki Wykład XVI Object Pascal Obiekty
Sem II Transport, Podstawy Informatyki Wykład XII Object Pascal Instrukcje sterujące
Podstawy Informatyki Wykład XIII Object Pascal Funkcje i procedury
Podstawy Informatyki Wykład XV Object Pascal Grafika
Podstawy Informatyki Wykład XII Object Pascal Instrukcje sterujące
Sem II Transport, Podstawy Informatyki Wykład XVIII Object Pascal Grafika
Podstawy Informatyki Wykład XIV Object Pascal Tablice, rekordy i zbiory
Sem II Transport, Podstawy Informatyki Wykład XVI i XVII Object Pascal Tablice, rekordy i zbiory
Sem II Transport, Podstawy Informatyki Wykład XIV i XV Object Pascal Funkcje i procedury
Sem II Transport, Podstawy Informatyki Wykład XIX i XX Object Pascal Obiekty
Podstawy Informatyki Wykład X Object Pascal Jezyki programowania, Proste typy danych
Podstawy Informatyki Wykład XIX Bazy danych
Podstawy Informatyki Wykład V Struktury systemów komputerowych
Zagadnienia egzamin podstawy informatyki, Elektronika i Telekomunikacja, z PENDRIVE, Politechnika -
Podstawy informatyki, wykład 7

więcej podobnych podstron