Delphi __ Kompendium __ Roz15.pdf

(1000 KB) Pobierz
Delphi :: Kompendium :: Roz...
Delphi :: Kompendium :: Rozdział 15 - 4programmers.net http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_15
Logowanie | Rejestracja | Forum | Pomoc | Reklama | Szukaj
Strona główna :: Delphi :: Kompendium
Rozdział 15
Edytuj Historia
Delphi
Artykuły
Kompendium
Gotowce
FAQ
.NET
Turbo Pascal
FAQ
PHP
FAQ
Java
FAQ
C/C++
Artykuły
FAQ
C#
Wprowadzenie
Assembler
FAQ
(X)HTML
CSS
JavaScript
Z pogranicza
Algorytmy
WIĘCEJ »
Tworzenie komponentów
Poprzedni rozdział stanowił wprowadzenie do technik tworzenia komponentów. Omówiłem w nim rolę VCL i CLX
w programowaniu w Delphi oraz hierarchię klas. Przyznam, mogło to być nieco nudne ze względu na dużą
dawkę wiedzy teoretycznej. Tym razem zajmiemy się już programowaniem własnych projektów i
zastosowaniem ich w praktyce.
Spis treści
1 Tworzenie nowego komponentu
2 Edycja kodu
3 Konstruktory i destruktory
4 Właściwości
4.1 Klauzula default
4.2 Klauzula stored
4.3 Klauzula nodefault
4.4 Właściwość wyliczeniowa
4.5 Właściwość zbiorowa
5 Zdarzenia
5.1 Definiowanie własnych zdarzeń
6 Ikona dla komponentów
7 Przykładowy komponent
7.1 Ogólny zarys klasy
7.2 Komunikaty
7.3 Kod źródłowy komponentu
8 Instalacja komponentów
9 Demonstracja możliwości komponentu TURLabel
10 Zachowanie komponentu
11 Komponenty graficzne
11.1 Ogólny zarys klasy komponentu
11.2 Kod źródłowy komponentu
12 Pakiety komponentów
13 Podsumowanie
Delphi
C/C++
Turbo Pascal
Assembler
PHP
Programy
Dokumentacja
Kursy
Komponenty
WIĘCEJ »
W tym rozdziale:
wykorzystasz w sposób praktyczny wiedzę na temat komponentów;
zaprojektujesz swój pierwszy komponent ? TURLabel;
nauczysz się instalować komponenty;
zaprojektujesz komponent graficzny.
Tworzenie nowego komponentu
Już dłuższy czas pracujesz z Delphi, powinieneś więc zauważyć istnienie menu Component . Nas na tym etapie
zainteresują jedynie dwie pozycje tego menu ? New Component i Install Component . Pierwsze polecenie służy
do stworzenia nowego projektu komponentu, natomiast za pomocą drugiego możemy zainstalować już
istniejący komponent. Po wybraniu tej opcji na palecie komponentów zostanie utworzona nowa ikonka ?
wówczas komponent będzie działał jak zwykły komponent VCL.
Zajmijmy się jednak tworzeniem nowego komponentu. Z menu Component wybierz New Component . Na
ekranie zobaczysz wówczas takie okienko, jakie zostało przedstawione na rysunku 15.1.
Rysunek 15.1. Tworzenie nowego komponentu
W pierwszym polu z listy rozwijalnej należy wybrać komponent, który będzie stanowił klasę bazową dla
naszego nowego obiektu. Ja z tej listy wybrałem klase TLabel . Jeżeli chcesz tworzyć komponent od początku,
wybierz pozycję TComponent . Jest to bazowa klasa dla wszystkich komponentów, zawierająca parę potrzebnych
czasem procedur i funkcji.
1 z 14
2009-03-14 15:49
77982048.009.png 77982048.010.png 77982048.011.png 77982048.012.png 77982048.001.png 77982048.002.png 77982048.003.png
Delphi :: Kompendium :: Rozdział 15 - 4programmers.net http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_15
W kolejnym polu ? Class Name ? musisz wpisać nazwę nowego komponentu. Pamiętaj, że wedle obowiązującej
zasady należy poprzedzić nazwę literą T. Pole Palette Page określa, na jakiej palecie zostanie zainstalowany
komponent. Unit file name to ścieżka do katalogu, w którym zostaną zapisane nowe pliki z komponentem.
Zawartość tego pola pozostawiłem niezmienioną. I wreszcie ostatnie pole określa ścieżkę do katalogu, gdzie
znajdować się będą potrzebne do kompilacji pliki komponentu. ${DELPHI} oznacza domyślną ścieżkę do pliku
programu Delphi.
Po naciśnięciu przycisku Install komponent zostanie zainstalowany na wybranej palecie, natomiast po
naciśnięciu przycisku OK w edytorze kodu zostanie jedynie wyświetlona zawartość kodu komponentu.
Edycja kodu
Copyright © 2000-2006 by Coyote Group 0.9.3-pre3
Czas generowania strony: 1.5802 sek. (zapytań SQL:
11)
Po wykonaniu operacji opisanych w poprzednim punkcie w edytorze kodu powinien zostać wyświetlony taki
kod, jak w listingu 15.1.
Listing 15.1. Podstawowy kod komponentu TURLabel
unit URLabel;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, StdCtrls;
type
TURLabel = class ( TLabel )
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
end ;
procedure Register ;
implementation
procedure Register ;
begin
RegisterComponents ( 'Samples' , [ TURLabel ]) ;
end ;
end .
Kluczowe znaczenie ma procedura Register . Następuje w niej zarejestrowanie komponentu realizowane przez
polecenie RegisterComponents . Pierwszy parametr oznacza nazwę palety. Drugi parametr to nazwy
komponentów do zainstalowania. Muszą one być wpisane w nawiasie kwadratowym, gdyż w tym wypadku
występują jako elementy tablicy. Taki zapis jest konieczny, gdyż jeden moduł ? w tym wypadku URLabel ?
może zawierać kilka klas (komponentów).
Podczas wpisywania zakładki dla tworzonego komponentu nie musisz podawać nazwy
zakładki już istniejącej ? jeżeli wpiszesz nazwę nieistniejącej zakładki, zostanie ona
utworzona przez Delphi.
Zwróć uwagę, że w klasie możesz używać nowej sekcji ? published . Ta sekcja może zawierać metody, które
będą wyświetlone w Inspektorze Obiektów.
Konstruktory i destruktory
Komponenty, podobnie jak zwykłe klasy, posiadają konstruktory oraz destruktory. Nie są to co prawda
obowiązkowe elementy klasy, gdyż nawet jeśli ich nie zadeklarujemy, to i tak komponent będzie posiadał
domyślny konstruktor z klasy bazowej (najwyżej ? TObject ). W przypadku komponentu konstruktor winien
mieć parametr AOwner (typu TComponent ), który zawierałby wskazanie komponentu (lub formularza) rodzica:
public
constructor Create ( AOwner : TComponent ) ; override ;
destructor Destroy; override ;
Jak widzisz, zarówno konstruktor, jak i destruktor są opatrzone klauzulą override , co znaczy, że są
przedefiniowane (była o tym mowa w 3. rozdziale książki) ? możemy dla nich wpisać kod:
constructor TURLabel. Create ( AOwner : TComponent ) ;
begin
inherited Create ( AOwner ) ;
{ podczas wywoływania konstruktora dla właściwości przypisz domyślny tekst }
FURL := 'http://4programmers.net' ;
end ;
destructor TURLabel. Destroy ;
begin
inherited ;
end ;
W tym miejscu oprócz typowego utworzenia obiektu (działanie konstruktora) następuje również przydzielenie
wartości dla właściwości FURL.
Właściwości
Właściwości komponentów służą do przechowywania wartości różnych typów. Jednak jeśli chcemy, aby
właściwości były widoczne w Inspektorze Obiektów, należy użyć kolejnej sekcji w klasie ? sekcji published :
property URL : String read FURL write FURL;
2 z 14
2009-03-14 15:49
RSS | Forum | Pastebin |
Regulamin | Pomoc | Usuń
cookies | Prawa autorskie |
Kontakt | Reklama
77982048.004.png 77982048.005.png
Delphi :: Kompendium :: Rozdział 15 - 4programmers.net http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_15
Właściwość należy oznaczyć słowem kluczowym property . W tym wypadku właściwość URL będzie typu String .
Zwykło się także definiować zmienne pomocnicze, których deklaracje umieszcza się w sekcji private . Nazwy
owych zmiennych umieszczane są po słowach kluczowych read i write . W ten sposób łatwo utworzyć jakąś
właściwość tylko do odczytu (pozostawiając jedynie klauzulę read ) lub tylko do zapisu (klauzula write ), albo
też zarówno do zapisu, jak i do odczytu (zarówno read , jak i write ).
Regułą stało się już specjalne nazewnictwo zmiennych pomocniczych, polegające na
dodawaniu przed nazwą litery F.
Klauzula default
Podczas pisania samego komponentu istnieje możliwość określania domyślnej wartości za pomocą klauzuli
default .
property Count : Integer read FCount write FCount default 1 ;
W takim wypadku domyślna wartość właściwości Count to 1.
Klauzula default obejmuje jedynie typy liczbowe i zbiory ( set ) ? nie obsługuje natomiast łańcuchów String .
Klauzula stored
W przypadku typów typu Boolean używa się klauzuli stored , a nie default ? np.:
property DoIt : Boolean read FDoIt write FDoIt stored False ;
Jeśli nie skorzystamy z klauzuli stored , program za domyślną wartość dla właściwości przyjmie True .
Klauzula nodefault
Klauzula nodefault jest przeciwieństwem defulat ? oznacza, że właściwość nie będzie miała wartości
domyślnej. Stosowana jest jedynie w niektórych przypadkach, gdy klasa bazowa, z której korzysta nasz
komponent, posiada właściwość domyślną.
TBaseClass = class
private
FProp : Integer ;
published
property Prop : Integer read FProp write FProp default 1 ;
end ;
TMyClass = class ( TBaseClass )
private
FProp : Integer ;
published
property Prop : Integer read FProp write FProp nodefault ;
end ;
W takim wypadku klasa TMyClass także będzie posiadać właściwość Prop , tyle że nie będzie już ona zawierała
wartości domyślnej.
Właściwość wyliczeniowa
O właściwościach wyliczeniowych wspominałem w poprzednim rozdziale, lecz tym razem zajmiemy się ich
deklaracją. Przypominam, że właściwość wyliczeniowa to lista rozwijalna z możliwymi wartościami (rysunek
15.2).
Rysunek 15.2. Właściwość wyliczeniowa
W języku Object Pascal właściwości wyliczeniowe to w rzeczywistości deklaracje typu set of .
type
TSetCarOption = ( coFiat, coOpel, coPorshe ) ;
TSetCarOptions = set of TSetCarOption;
TMyClass = class ( TComponent )
private
FCar : TSetCarOptions;
protected
{ Protected declarations }
public
{ Public declarations }
3 z 14
2009-03-14 15:49
77982048.006.png
Delphi :: Kompendium :: Rozdział 15 - 4programmers.net http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_15
published
property Car : TSetCarOptions read FCar write FCar default [ coFiat ] ;
end ;
Zadeklarowaliśmy właśnie właściwość wyliczeniową typu TSetCarOptions . W tym wypadku właściwość Car
będzie posiadała domyślną wartość ? coFiat .
Właściwość zbiorowa
Przykład właściwości zbiorowej przedstawiony został na rysunku 15.3.
Rysunek 15.3. Właściwość zbiorowa
Deklarowanie właściwości zbiorowej w rzeczywistości wiąże się z zadeklarowaniem nowego typu danych (klasy).
type
TCarClass = class ( TPersistent )
private
FFuel : Integer ;
FCarName : String ;
published
property CarName : String read FCarName write FCarName;
property Fuel : Integer read FFuel write FFuel;
end ;
TMyClass = class ( TComponent )
private
FCar : TCarClass;
protected
{ Protected declarations }
public
constructor Create ( AOwner : TComponent ) ; override ;
destructor Destroy; override ;
published
property Car : TCarClass read FCar write FCar;
end ;
Nasz komponent będzie posiadał właściwość zbiorową Car . Po jej rozwinięciu w Inspektorze Obiektów pojawią
się właściwości z klasy TCarClass . Mamy do czynienia z nową klasą TCarClass i przed skorzystaniem z jej
właściwości należy ją utworzyć (wywołać konstruktor):
constructor TMyClass. Create ( AOwner: TComponent ) ;
begin
inherited Create ( AOwner ) ;
FCar := TCarClass. Create ; // utworzenie klasy
end ;
destructor TMyClass. Destroy ;
begin
FCar. Free ; // zwolnienie
inherited ;
end ;
Zdarzenia
Zdarzenia, podobnie jak właściwości naszego komponentu, muszą być deklarowane w sekcji published ? tak,
aby były widoczne w Inspektorze Obiektów ? np. w ten sposób:
property OnMouseEnter : TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
property OnMouseLeave : TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
Zapis ten jest dość dziwny, gdyż sprawia wrażenie, jakbyśmy deklarowali zwykłe właściwości, tyle że typu
TNotifyEvent . Typ TNotifyEvent jest zadeklarowany w module Classes :
type TNotifyEvent = procedure ( Sender: TObject ) of object ;
Można powiedzieć, że określa on procedurę zdarzeniową, która miałaby tylko jeden parametr ? Sender . Już
nieraz podczas lektury tej książki miałeś okazję zapoznać się z moją opinią o tym, że dana procedura
zdarzeniowa musi mieć parametr Sender . Teraz już wiesz, że zdarzenie OnClick jest typu TNotifyEvent i stąd
musi posiadać parametr Sender .
Definiowanie własnych zdarzeń
Czasem może przytrafić się sytuacja, gdy w naszym komponencie będzie wymagane zdarzenie zawierające
więcej niż jeden parametr ? po prostu będzie umożliwiało użytkownikowi przekazanie jakiś funkcji. W takim
wypadku konieczne stanie się zadeklarowanie nowego typu zdarzenia:
4 z 14
2009-03-14 15:49
77982048.007.png
Delphi :: Kompendium :: Rozdział 15 - 4programmers.net http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_15
type
TMyEvent = procedure ( Sender: TObject ; X : Integer ) of object ;
Taka składnia ? tj. umieszczenie frazy of object na końcu ? jest obowiązkowa. Teraz oprócz zwykłego
parametru Sender zdarzenie będzie posiadać także parametr X . Co z nim zrobimy? To już zależy od
programisty.
Gdy chcesz, aby jakieś działanie komponentu spowodowało wystąpienie zdarzenia, możesz zastosować po
prostu taki kod:
OnURLClick ( Self , 1 ) ;
A zatem pierwszym parametrem Self zastępujemy wymagany parametr typu TObject , natomiast drugi
parametr przekazany wraz ze zdarzeniem to cyfra 1.
Ikona dla komponentów
Po zainstalowaniu komponentu Delphi przydzieli dla niego swoją własną ikonę. W każdym wypadku można to
zmienić, przypisując temu komponentowi osobną ikonę. Wystarczy skorzystać z programu do tworzenia bitmap.
Możesz użyć np. programu Image Editor, którego już wcześniej używaliśmy przy okazji tworzenia różnych
zasobów.
W przypadku, gdy tworzysz zasoby dla komponentu, tworzysz plik .DCR, a nie .RES! Uważaj
na to! Także słowo ikona komponentu jest tylko terminem umownym, gdyż w zasobie
musisz stworzyć NIE ikonę, ale BITMAPĘ o rozmiarach 24×24 piksele.
Stwórz więc nowy plik .DCR, a w nim bitmapę 24´24 piksele, na której narysuj jakiś obrazek. Cały zasób
następnie włącz do kodu komponentu za pomocą dyrektywy {$R ZASOBY.DCR} .
Należy pamiętać o jeszcze jednej kwestii związanej z nazewnictwem bitmapy ? musi się ona
nazywać tak samo, jak klasa (komponent), która wykorzystuje tę ikonę. A zatem jeżeli
komponent nazywa się TURLabel , bitmapa musi również nosić nazwę TURLABEL .
Przykładowy komponent
Właściwie możesz już przystąpić do napisania swojego pierwszego komponentu. Nie będzie to nic
nadzwyczajnego ? po prostu etykieta, która jest w rzeczywistości odnośnikiem do strony WWW. Jej kliknięcie
spowoduje otwarcie żądanego adresu.
Ogólny zarys klasy
W przypadku, gdy masz już otwarty nowy projekt, powinieneś mieć w edytorze ?czysty? kod tworzonego
właśnie komponentu. Kod naszej nowej klasy TURLabel powinien przedstawiać się w następujący sposób:
TURLabel = class ( TLabel )
private
FURL : String ;
FParametr : String ;
FOnMouseEnter, FOnMouseLeave : TNotifyEvent;
FOnURLClick : TClickEvent;
FDefaultFontColor : TColor;
FDefaultFontStyle : TFontStyles;
protected
procedure CmMouseEnter ( var Msg : TMessage ) ; message CM_MOUSEENTER;
procedure CmMouseLeave ( var Msg : TMessage ) ; message CM_MOUSELEAVE;
procedure WMLButtonDown ( var Msg : TMessage ) ; message WM_LBUTTONDOWN;
public
constructor Create ( AOwner : TComponent ) ; override ;
destructor Destroy; override ;
published
property URL : String read FURL write FURL; // URL do otwarcia
property Parametr : String read FParametr write FParametr; // dodatkowy parametr
property OnMouseEnter : TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
property OnMouseLeave : TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
property OnURLClick : TClickEvent read FOnURLClick write FOnURLClick;
end ;
Komponent będzie posiadał standardową właściwość URL, określającą adres strony, która ma zostać otwarta.
Zdarzenia OnMouseEnter oraz OnMouseLeave będą występowały w momencie umieszczenia kursora myszy nad
obiektem lub przemieszczenia kursora znad obiektu. Dodatkowe zdarzenie OnURLClick wystąpi, gdy użytkownik
kliknie odnośnik. Będzie ono przekazywało do programu współrzędne pozycji kursora X i Y, pobrane w
momencie naciśnięcia przycisku myszy.
Komunikaty
Do przechwycenia momentu umieszczenia kursora nad obiektem niezbędne będzie skorzystanie z
komunikatów, a ściślej mówiąc z CM_MOUSEENTER oraz CM_MOUSELEAVE .
procedure TURLabel. CMMouseEnter ( var Msg : TMessage ) ;
begin
{ jeżeli wykorzystane jest zdarzenie FOnMouseEnter ? wywołaj je }
if Assigned ( FOnMouseEnter ) then OnMouseEnter ( Self ) ;
FDefaultFontColor := Font. Color ; // pobierz do zmiennej kolor czcionki
FDefaultFontStyle := Font. Style ; // pobierz styl czcionki (pogrubiony, podkreślony)
Cursor := crHandPoint; // zmień kursor
Font. Color := clBlue; // zmień kolor czcionki
Font. Style := Font. Style + [ fsUnderline ] ; // dodaj podkreślenie
end ;
procedure TURLabel. CmMouseLeave ( var Msg : TMessage ) ;
5 z 14
2009-03-14 15:49
77982048.008.png
Zgłoś jeśli naruszono regulamin