Delphi Kompendium Roz14

background image

Logowanie | Rejestracja | Forum | Pomoc | Reklama | Szukaj

Strona główna :: Delphi :: Kompendium

Edytuj

Historia

Rozdział 14

Komponenty VCL i CLX

Zanim przejdziemy do właściwego procesu tworzenia komponentów, konieczne będzie dokładne zapoznanie się
z zasadami ich działania. Co prawda zarówno o klasach, jak i o VCL mówiłem już w rozdziale 3., lecz tamta
wiedza była konieczna do dalszego projektowania aplikacji w Delphi. Tym razem poznasz architekturę
komponentów VCL oraz CLX ze strony projektanta ? dowiesz się, jak to wszystko działa i jak jest ze sobą
połączone.

Spis treści

1 Czym jest komponent?

2 VCL

3 CLX

3.1 Tworzenie aplikacji opartych na CLX

3.2 CLX a VCL

3.3 Architektura CLX

4 Windows a Linux

4.1 Kompilacja warunkowa

5 Rodzaje komponentów

5.1 Komponenty wizualne

5.2 Komponenty niewizualne

5.3 Komponenty graficzne

6 Hierarchia komponentów

6.1 TObject

6.1.1 Metody klasy TObject

6.1.1.1 ClassName

6.1.1.2 ClassNameIs

6.1.1.3 ClassInfo

6.1.1.4 ClassParent

6.1.1.5 ClassType

6.1.1.6 FieldAddress

6.1.1.7 MethodAddress

6.2 TPersistent

6.2.1 Metoda Assign

6.2.2 Metoda AssignTo

6.2.3 Metoda DefineProperties

6.3 TComponent

6.3.1 Właściwości klasy TComponent

6.3.1.1 ComponentCount

6.3.1.2 ComponentIndex

6.3.1.3 Components

6.3.1.4 ComponentState

6.3.1.5 Name

6.3.1.6 Owner

6.3.2 Metody klasy TComponent

6.4 TControl

6.4.1 Właściwości klasy TControl

6.5 TWinControl i TWidgetControl

6.5.1 Właściwości klas TWinControl i TWidgetControl

6.5.2 Zdarzenia

6.6 Klasy TCustom

6.7 TGraphicControl

7 Budowa komponentu

7.1 Właściwości

7.1.1 Rodzaje właściwości

7.2 Zdarzenia

7.3 Metody

8 RTTI

8.1 Właściwości obiektu

8.2 Dokładniejsze informacje o obiekcie

9 Podsumowanie

W tym rozdziale:

dowiesz się, jak funkcjonuje klasa VCL;
dowiesz się, czym jest biblioteka CLX;
poznasz elementarne metody i właściwości podstawowych klas.

Czym jest komponent?

Delphi jako środowisko wizualne udostępnia różne kontrolki ? tzw. komponenty, służące do szybkiego
projektowania aplikacji. Komponenty są ?klockami?, którymi posługuje się programista w procesie budowania
aplikacji.

Patrząc na komponenty ze strony projektanta aplikacji, mamy do czynienia z wygodnymi i łatwymi w obsłudze
narzędziami. Nie interesuje nas, jak one działają i jaki kod znajduje się ?w środku?. Ważne są zdarzenia,
metody, właściwości i zadania, jakie spełniają. W rzeczywistości wiele komponentów jest ze sobą powiązanych
i korzysta z tych samych modułów, klas i bibliotek.

Kluczem do poznania VCL oraz CLX jest zrozumienie zasady działania różnych typów danych, poznanie

RSS | Forum | Pastebin |

Regulamin | Pomoc | Usuń

cookies | Prawa autorskie |

Kontakt | Reklama

Copyright © 2000-2006 by Coyote Group 0.9.3-pre3
Czas generowania strony: 0.9116 sek. (zapytań SQL:
12)

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

1 z 12

2009-03-14 15:46

background image

hierarchii klas itp.

VCL

VCL to Visual Component Library (wizualna biblioteka komponentów). Programowanie w Delphi nie byłoby takie
łatwe dla początkujących, gdyby nie VCL. Poprzednikiem VCL była biblioteka OWL (Object Windows Library),
znajdująca się w Turbo Pascalu. Dla użytkownika wywołanie konstruktora Create to tylko jeden wiersz kodu,
powodujący utworzenie komponentu (obiektu). W rzeczywistości na podstawie kodu VCL wykonywany jest
szereg innych procedur, które ostatecznie dają efekt w postaci utworzenia komponentu.

CLX

Opublikowanie Delphi 6 było czymś niezwykłym ze względu na wprowadzenie biblioteki CLX (Component Library
for Cross-Platform
), czyli międzyplatformowej biblioteki komponentów. Pojawienie się CLX wiązane jest z
wydaniem nowego środowiska programistycznego Kylix, przeznaczonego dla systemu operacyjnego Linux.
Programowanie w Kyliksie jest niezwykle podobne do programowania w Delphi ? nawet interfejs jest ten sam.
Kylix również ? tak jak Delphi ? wykorzystuje język Object Pascal, co mogło trochę dziwić w momencie edycji
produktu. W końcu Linux jest platformą, na której króluje C++.

W każdym razie w związku z pojawieniem się Kyliksa oraz biblioteki CLX przekroczona została pewna bariera ?
od tej pory możliwe jest tworzenie aplikacji zgodnych zarówno z systemem Windows, jak i Linuks.

Tworzenie aplikacji opartych na CLX

Aby stworzyć aplikację działającą w oparciu o CLX, wystarczy z menu File wybrać polecenie New/CLX
Application
. Wówczas zmieniona zostanie zawartość palety komponentów oraz edytora kodu.

CLX a VCL

Sam akronim VCL może dawać do zrozumienia, że mamy do czynienia z całkowicie wizualną biblioteką. W
rzeczywistości tak nie jest, bo VCL zawiera również komponenty, które nie są widoczne, ale jednak odpowiadają
za wykonywanie jakichś czynności. Pisząc programy działające w systemie Windows, korzystamy ze
standardowych kontrolek tego systemu (chociażby kontrolka TButton), zawartych w bibliotece User32.dll lub
CommCtrl32.dll. Natomiast w przypadku CLX komponenty z tej biblioteki są oparte na tzw. widgetach,
zawartych w bibliotece Qt. Owa biblioteka zawiera niezależne klasy, które swoim wyglądem oraz
funkcjonalnością przypominają standardowe kontrolki Windows.

Słowo widget jest skrótem słów Window Gadget.

Architektura CLX

Architektura CLX jest nieco bardziej złożona niż VCL. Mamy tu bowiem kilka grup komponentów. Oprócz grupy
wizualnej ? VisualCLX ? istnieją jeszcze komponenty BaseCLX (moduły wspólne dla Delphi i Kyliksa), DataCLX
(komponenty zapewniające dostęp do technologii dbExpress ? będziemy o tym mówić w kolejnej części książki)
oraz NetCLX (technologie internetowe).

VCL jest zbudowany na bazie kontrolek WinAPI, zawartych m.in. w bibliotekach User32.dll oraz ComCtrl32.dll.
W przypadku CLX grupa komponentów VisualCLX jest oparta na bibliotece Qt.

Hierarchia klas jest ona bardzo podobna do hierarchii komponentów VCL. Dodano parę nowych klas, inne
zamieniono miejscami, lecz starano się zachować maksymalną kompatybilność pomiędzy CLX i VCL ? tak, aby
przenoszenie kodu odbywało się z jak najmniejszym nakładem pracy.

Windows a Linux

Można by przypuszczać, że dla programisty tworzącego swoje aplikacje w języku Object Pascal nie ma
znaczenia, na jakiej platformie będzie uruchamiany ów program. Oczywiście należy jednak pamiętać o pewnych
elementach charakterystycznych dla danego systemu. Przykładem może być konieczność zwracania uwagi na
nazewnictwo plików w Linuksie ? w systemie tym rozróżniane są np. nazwy modułów na liście

uses

.

W systemie Linux używany jest inny znak separatora katalogów. W Windows jest to znak backslash (\), a
w Linuksie ? slash (/). Właściwy dla konkretnej platformy znak można odczytać ze stałej PathSeparator.
Pamiętasz, jak podczas omawiania bibliotek DLL wspominałem o konwencjach wywołania

stdcall

,

safecall

i

cdecl

? W Kyliksie należy zmienić tę klauzulę na

cdecl

, gdyż tylko taka forma jest prawidłowa.

Tworząc programy w Kyliksie, należy unikać modułów oraz funkcji charakterystycznych dla Windows ?
np. modułów Windows, ActiveX, ComServ, ComObj itp. ? gdyż nie odnajdziemy tam takich technologii
jak BDE, COM czy ActiveX.
Bardzo ważne jest zapamiętanie, że w Linuksie nie możemy korzystać z komunikatów. Niedopuszczalne
jest zatem wysyłanie komunikatów czy ich przechwytywanie ? np. WM_CHAR itp.
Większość klas nazywa się tak samo. Pamiętaj jednak, że klasa TWinControl w CLX nazywa się

TWidgetControl

. Ze względów kompatybilności zachowano jednak również klasę TWinControl, która jest

równoważna klasie TWidgetControl.
Unikaj stosowania funkcji typowych dla Windows:

Win32Check

,

RaiseLastWin32Error

.

W systemie Linux nie ma Rejestru ? nie możesz więc korzystać z klasy TRegistry.
Nazwy modułów CLX rozpoczynają się od litery Q ? np. QControls.
System Linux nie używa liter do określania dysków, tak jak ma to miejsce w Windows. Wszystko opiera
się na charakterystycznym systemie plików, gdzie istnieją tylko katalogi główne ? np. /usr

Kompilacja warunkowa

Zarówno w Delphi, jak i w Kyliksie istnieje możliwość wprowadzenia charakterystycznego dla danej platformy
kodu. Wszystko dzięki tzw. symbolom kompilacji warunkowej.

{$IFDEF LINUX}
// kod dla Linuksa
{$ENDIF}

Dla systemu Linux takim symbolem jest LINUX, a dla Windows może to być WIN32 i MSWINDOWS:

{$IFDEF WIN32}
// kod dla Windows
{$ENDIF}

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

2 z 12

2009-03-14 15:46

background image

Dzięki takiemu prostemu rozwiązaniu można wprowadzać charakterystyczne dla danej platformy elementy
kodu.

Rodzaje komponentów

Komponenty w Delphi dzielą się na wizualne oraz niewizualne ? bynajmniej nie chodzi tutaj o właściwość
Visible

, której zmiana na True powoduje ukrycie komponentu.

Komponenty wizualne

Nieprzypadkowo dla określenia komponentu wizualnego często używam w tej książce słowa kontrolka (control).
Należy zdać sobie sprawę z tego, że kontrolka to obiekt wizualny, będący w stanie odbierać komunikaty od
użytkownika. Kontrolki mają właściwości mogące określić ich położenie względem projektanta formularzy. Mogą
być także aktywowane (focus). Komponenty wizualne wywodzą się z klasy TControl. Przykładami kontrolek
wizualnych są TButton, TLabel, TListView, TComboBox itp.

Komponenty niewizualne

Komponentem jest każdy obiekt, mogący znaleźć się w palecie komponentów. Niektóre z tych obiektów są
widoczne po uruchomieniu programu, niektóre jednak nie. Komponenty niewidoczne wywodzą się z klasy
TComponent

, lecz mimo tego, że ich nie widać, pełnią inną funkcję, często o wiele ważniejszą niż rola obiektów

wizualnych. Przykładem komponentów niewidocznych jest komponent TTimer, TOpenDialog (ogólnie wszystkie
komponenty z palety Dialogs) oraz komponenty z palety Indy.

Komponenty graficzne

Niektóre komponenty Delphi mimo swego charakteru wizualnego nie posiadają zdolności interakcji z
użytkownikiem ? nie mogą więc stać się aktywne. Nie posiadają także uchwytu, a ich klasą bazową jest
TGraphicControl

.

Przykładem takich komponentów są TPaintBox i TImage.

Hierarchia komponentów

Na rysunku 14.1 przedstawiona została hierarchia komponentów VCL. Naturalnie jest to tylko fragment
ogromnej pajęczyny klas.

Rysunek 14.1. Hierarchia komponentów VCL

W CLX ze względów kompatybilności starano się zachować identyczne nazewnictwo klas. Różnica pojawia się w
klasie TWinControl, która w CLX nosi nazwę TWidgetControl. Pamiętaj o tym, że w CLX nie ma klasy

TRegistry

, lecz możesz korzystać z klasy TRegINIFile.

TObject

Klasa TObject jest podstawowym fundamentem całej struktury VCL oraz CLX. Zawiera wiele podstawowych
metod, obecnych we wszystkich klasach. Wszystko dzięki dziedziczeniu ? w czasie, gdy pozostałe klasy
dziedziczą po klasie TObject, przejmują jej wszystkie metody. Klasa ta odpowiada za tak podstawowe
czynności, jak:

tworzenie i usuwanie instancji komponentu,
alokację i zwalnianie potrzebnej pamięci,
obsługę komunikatów,
zwracanie informacji na temat rodzaju klasy, nazwy itp.

Metody klasy TObject

Klasa TObject definiuje jedynie metody, które mogą być później używane przez wszystkie inne kontrolki VCL.
Spis najważniejszych metod klasy TObject znajduje się poniżej.

ClassName

class function ClassName:

ShortString

;

Owa funkcja zwraca nazwę klasy ? przykład:

ShowMessage

(

Button1.

ClassName

)

;

Powyższy kod spowoduje wyświetlenie rzeczywistej nazwy klasy, czyli TButton.

ClassNameIs

class function ClassNameIs

(

const Name:

string

)

:

Boolean

;

Funkcja sprawdza, czy podana w parametrze klasa odpowiada tej, z której jest wywoływana funkcja. Najlepiej
objaśnić to na przykładzie:

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

3 z 12

2009-03-14 15:46

background image

Button1.

ClassNameIs

(

?TButton?

)

; // funkcja zwróci True

Button1.

ClassNameIs

(

?

TObject

?

)

; // funkcja zwróci False

ClassInfo

class function ClassInfo:

Pointer

;

Funkcja zwraca wskaźnik do tablicy zawierającej informacje takie jak typ obiektu, właściwości itp. Wrócimy do
tego nieco później.

ClassParent

class function ClassParent: TClass;

Informacja o klasie bazowej dla naszego komponentu jest zwracana przez funkcję ClassParent. Dzięki owej
funkcji możemy odwołać się do innych właściwości klasy bazowej, nie znając jej podczas tworzenia programu.

ClassType

function ClassType: TClass;

Funkcja działa podobnie jak ClassParent. Jedyna różnica polega na tym, że zwraca ona informacje na temat
klasy, z której jest wywoływana ? np.:

ShowMessage

(

Button1.

ClassType

.

ClassName

)

;

Po wykonaniu takiego kodu w okienku wyświetlony zostanie napis TButton. Inna sprawa, że taki sam efekt
uzyskamy, korzystając z funkcji ClassName.

FieldAddress

function FieldAddress

(

const Name:

ShortString

)

:

Pointer

;

Funkcja FieldAddress zwraca wskaźnik do właściwości znajdującej się w pamięci. Nazwa właściwości musi
zostać podana w parametrze.

MethodAddress

class function MethodAddress

(

const Name:

ShortString

)

:

Pointer

;

Funkcja działa podobnie jak FieldAddress, tyle że ta zwraca wskaźnik do metody umieszczonej w pamięci ? nie
zaś właściwości.

Więcej opisów metod klasy TObject możesz znaleźć w systemie pomocy Delphi lub (w
języku polskim) pod adresem

http://4programmers.net/Delphi

TPersistent

Klasą drugą po TObject w całej hierarchii jest TPersistent. Oczywiście większość metod dziedziczy po

TObject

, ale wprowadza także swoje metody.

Klasy TPersistent możesz użyć jako klasy bazowej w momencie, gdy deklarujesz klasy, które nie mają być
komponentem. Jaka jest więc różnica między TObject a TPersistent? Otóż klasa TPersistent może być
przodkiem dla wszystkich klas mogących zapisywać wartości do właściwości, które następnie mogą być
przechowywane w pliku *.dfm (lub *.xfm ? dla Kyliksa).

Metoda Assign

procedure

Assign

(

Source: TPersistent

)

;

virtual;

Metoda Assign, obecna w klasie TPersistent, powoduje skopiowanie danych (właściwości) z jednego obiektu
do drugiego.

Metoda AssignTo

procedure AssignTo

(

Dest: TPersistent

)

;

virtual;

AssignTo

działa odwrotnie niż procedura Assign. Powoduje skopiowanie danych do innego obiektu, określonego

w parametrze Dest.

Metoda DefineProperties

procedure DefineProperties

(

Filer: TFiler

)

;

virtual;

Procedura DefineProperties umożliwia przechowanie w pliku *.dfm dodatkowych danych ? tym pojęciem

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

4 z 12

2009-03-14 15:46

background image

zajmiemy się kolejnym rozdziale.

TComponent

Klasa TComponent, jak można wywnioskować z nazwy, jest przodkiem wszystkich komponentów. Komponenty
dziedziczące po TComponent mogą:

być zintegrowane z IDE Delphi, w tym mogą być umieszczone na palecie komponentów;
jeden obiekt typu TComponent może posiadać inny obiekt (być jego rodzicem);
komponenty mogą być konwertowane na obiekty COM lub kontrolki ActiveX.

Obiekty COM są wynalazkiem firmy Microsoft, stąd obecne są jedynie na platformie Windows.

Klasa TComponent wprowadza szereg nowych właściwości oraz metod, obecnych później we wszystkich
komponentach (w końcu wszystkie komponenty pochodzą od klasy TComponent).

Właściwości klasy TComponent

Klasa TComponent zawiera wiele ciekawych właściwości, które przedstawiłem poniżej.

ComponentCount

property ComponentCount:

Integer

;

Właściwość ComponentCount zwraca liczbę obiektów umieszczonych na danym komponencie (rysunek 14.2.):

procedure TMainForm.

Button1Click

(

Sender:

TObject

)

;

begin
Application.

MessageBox

(

PChar

(

'Na formularzu znajdują się '

+

IntToStr

(

ComponentCount

)

+

'

komponenty),
'

Tak

', MB_OK)

end;

Rysunek 14.2. Program demonstrujący znaczenie właściwości ComponentCount

ComponentIndex

property ComponentIndex:

Integer

;

Inna właściwość klasy TComponent ? Components[] to tablica komponentów. Do konkretnego obiektu można się
odwołać, podając jego indeks. Taki indeks natomiast jest zwracany przez właściwość ComponentIndex.

ShowMessage

(

IntToStr

(

Button1.

ComponentIndex

))

;

W powyższym przypadku w okienku pojawi się cyfra 1 jako numer identyfikacyjny dla komponentu Button1.

Components

property Components

[

Index:

Integer

]

: TComponent;

Jak wspomniałem powyżej, jest to tablica wszystkich elementów (komponentów) umieszczonych na danym
obiekcie. Do konkretnej kontrolki można się odwołać, podając w nawiasie kwadratowym jej indeks:

Components

[

1

]

.

Free

;

Powyższy kod spowoduje zniszczenie obiektu określonego numerem 1.

ComponentState

property ComponentState: TComponentState;

Sygnalizuje stan komponentu. Może zwrócić wartości takie, jak przedstawione w tabeli 14.1.

Tabela 14.1. Możliwe elementy typu TComponentState

Element

Opis

csDesigning

Komponent jest w trakcie projektowania, np. jego właściwości są zmieniane

csDestroying

Komponent za chwilę zostanie zniszczony

csFixups

Komponent jest podłączony do innego komponentu znajdującego się na innym formularzu

csLoading

Komponent jest właśnie ładowany (tworzony)

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

5 z 12

2009-03-14 15:46

background image

csReading

Komponent odczytuje swoje właściwości ze strumienia (pliku *.dfm)

csWriting

Komponent zapisuje właściwości do strumienia

Name

property Name: TComponentName;

Definiuje unikatową w ramach formularza nazwę dla komponentu. Wartość jest przeznaczona zarówno do
zapisu, jak i do odczytu.

Owner

property Owner: TComponent;

Właściwość Owner jest wskazaniem obiektu-rodzica. Jeżeli przykładowo komponent kkjest umieszczony na
formularzu Form1, to dzięki takiej konstrukcji:

Button1.

Owner

...

można odwołać się do formularza Form1.

Metody klasy TComponent

Nowych metod wprowadzonych wraz z klasą TComponent jest bardzo wiele. Większość z nich być może nigdy
nie zostanie przez Ciebie użyta, gdyż służą np. do określenia pewnego stanu, w jakim ma znajdować się
komponent.

Na pewno najważniejszą metodą klasy TComponent jest konstruktor, który w odróżnieniu od klasy TObject
posiada dodatkowy parametr ? rodzica, czyli obiekt, na którym ma zostać utworzony nowy komponent.

constructor Create

(

AOwner: TComponent

)

;

virtual;

Utworzony w ten sposób konstruktor powinien zostać zwolniony metodą Free.

Do zwalniania komponentu nigdy nie używaj metody Destroy. Procedura Free przed
rzeczywistym zwolnieniem sprawdza, czy obiekt nie został już wcześniej zwolniony, co
zapobiega pojawieniu się błędu typu Access Violation.

Oto przykład utworzenia komponentu typu TButton w sposób dynamiczny:

procedure TForm1.

btnMakeClick

(

Sender:

TObject

)

;

var
MyButton : TButton;
begin
MyButton := TButton.

Create

(

Form1

)

;

MyButton.

Parent

:= Form1; // określenie rodzica

MyButton.

Caption

:=

'Przycisk 1'

;

end;

Rodzicem komponentu ustanawiamy formularz Form1. Jeżeli nie określiliśmy dokładniejszych danych ? np.
położenia komponentu ? zostanie on umieszczony w lewym, górnym rogu formularza.

Zwróć uwagę, że w powyższym kodzie nie ma instrukcji zwalniającej komponent ? Free. Wszystko dzięki temu,
że rodzicem nowego obiektu został formularz ? Form1. Przy zwalnianiu (zamykaniu) okna program najpierw
zwolni obiekty znajdujące się na nim, czyli m.in. nasz przycisk.

Ciekawą metodą klasy TComponent jest procedura FindComponent. Wspominam tu o niej, gdyż być może często
będziesz korzystał z jej zalet. Umożliwia ona bowiem odnalezienie jakiegoś komponentu na formularzu i
odwołanie się do konkretnych jego metod ? oto przykład:

procedure TMainForm.

btnMakeClick

(

Sender:

TObject

)

;

begin

Randomize

;

TEdit

(

FindComponent

(

'Edit'

+

IntToStr

(

Random

(

3

)

+

1

)))

.

Text

:=

'Nowa wartość'

;

end;

Powyższy kod spowoduje losowe odwołanie się do którejś z trzech umieszczonych na formularzu kontrolek typu
TEdit

ki zmianę jej właściwości Text (rysunek 14.3).

Rysunek 14.3. Losowe odwołanie się do której z kontrolek TEdit

TControl

Kolejną klasą w hierarchii obiektów VCL jest klasa TControl. Reprezentuje ona komponenty wizualne (jest
podstawową klasą dla tego rodzaju komponentów). Każdy obiekt typu TControl posiada dodatkowe właściwości
określające położenie komponentu: Top (położenie w pionie), Left (położenie w poziomie), Width (szerokość) i

Height

(wysokość).

Właściwości klasy TControl

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

6 z 12

2009-03-14 15:46

background image

Najważniejsze z właściwości (których nazwy możesz już pamiętać, gdyż są one wyświetlane w Inspektorze
Obiektów) przedstawiłem w tabeli 14.2.

Tabela 14.2. Najważniejsze właściwości klasy TControl

Właściwość

Opis

Align

Określa wyrównanie komponentu względem obiektu-rodzica

AutoSize

Określa wyrównanie komponentu względem obiektu-rodzica

Caption

Tytuł komponentu (tekst wyświetlany na obiekcie)

ClientHeight

Rozmiar obszaru roboczego (wysokość)

ClientWidth

Rozmiar obszaru roboczego (szerokość)

Color

Kolor tła obiektu

Cursor

Kursor wyświetlany po umieszczeniu wskaźnika myszy nad obiektem

Enabled

Określa, czy obiekt jest aktywny czy też nie

Font

Czcionka używana przez komponent

Hint

Wskazówka (etykietka podpowiedzi), pokazywana po umieszczeniu kursora nad obiektem

ShowHint

Właściwość określa, czy podpowiedzi mają być wyświetlane

Visible

Właściwość określa, czy komponent ma być widoczny podczas działania programu

Procedury i funkcje klasy TControl mają na celu przede wszystkim ustawienie danej wartości komponentu lub
odczytanie jej. Owa klasa posiada także wiele metod nakazujących w konsekwencji wystąpienie pewnego
zdarzenia (klasa TControl wprowadza zdarzenia, dzięki którym jesteśmy w stanie zareagować na konkretne
sytuacje).

TWinControl i TWidgetControl

Klasy TWinControl (VCL) oraz TWidgetControl (CLX) są bazowymi klasami dla kontrolek takich, jak przycisk
(TButton) i lista rozwijalna (TComboBox). Owe klasy są klasami bazowymi dla bardzo wielu kontrolek w Delphi.
Charakteryzują się następującymi właściwościami:

Umożliwiają wyświetlanie tekstu (np. TMemo).
Umożliwiają odbieranie od użytkownika zdarzeń, reagowanie np. na naciśnięcie przycisku czy wpisywanie
znaków za pomocą klawiatury.
Kontrolki mogą być rodzicem innych obiektów.
Kontrolki pochodzące z tych klas posiadają uchwyt (VCL) lub widget (CLX).

Właściwości klas TWinControl i TWidgetControl

Obie klasy definiują wiele właściwości, mających na celu zmodyfikowanie wyglądu danej kontrolki. Za przykład
może tu posłużyć właściwość BevelKind, która określa styl rysowania ramki dla komponentu. Do podobnych
właściwości tego typu należą także: BevelEdges, BevelInner, BevelOuter, BevelWidth i BorderWidth.

Ciekawą właściwością jest także Brush, która określa kolor i styl wypełniającego wnętrze komponentu.

Zdarzenia

Zdarzenia klasy TWinControl są związane z uzyskiwaniem dostępu do obiektu (aktywacja) czy też
wprowadzaniem tekstu z klawiatury. Są to zdarzenia: OnDockDrop, OnDockOver, OnEnter, OnExit, OnKeyDown,

OnKeyPress

i OnKeyUp.

Klasy TCustom

Wiele klas VCL ? np. TMemo ? posiada odpowiedniki w postaci klas bazowych, które rozpoczynają się
przedrostkiem Custom, np. TCustomMemo. Takie klasy pełnią wyłącznie rolę klas bazowych dla nowych
komponentów i nie są w praktyce wykorzystywane. Np. komponent TDBMemo także wywodzi się z klasy

TCustomMemo

? dzięki temu rozwiązaniu programiści oszczędzają wiele wierszy kodu, dziedzicząc w zwykły

sposób potrzebne metody i właściwości.

TGraphicControl

Jest to raczej specyficzny rodzaj kontrolek, a mianowicie komponent graficzny. Komponenty takie są oczywiście
komponentami wizualnymi, ale nie mogą być aktywne. Nie mogą także pełnić roli rodzica innych komponentów.
Śmiało można powiedzieć, że kontrolki tego typu są komponentami nieaktywnymi.

Natomiast każda kontrolka typu TGrpaphicControl ma przyporządkowane płótno (Canvas), którego
odświeżenie następuje za pomocą wywołania metody Repaint.

Budowa komponentu

Komponent w rzeczywistości jest klasą. Jest jednak klasą dość specyficzną, posiadającą określoną budowę, bez
której taka klasa nie byłaby po prostu komponentem.

Właściwości

W klasie właściwości służą do przechowywania w pamięci pewnej wartości. W przypadku komponentów wartości
standardowo wprowadzone w Inspektorze Obiektów są zapisywane w pliku *.dfm. Jednakże aby właściwości
były widoczne w Inspektorze Obiektów, należy użyć specjalnej sekcji ?

published

. O klasach mówiłem już w

rozdziale 3., lecz o sekcji published jedynie wówczas wspomniałem. Jeśli tworzysz komponenty i chcesz dodać
do nich właściwości, kod w sekcji published musi wyglądać tak:

TMojKomponent =

class

(

TLabel

)

private
FText :

String

;

procedure DoIt

(

Value :

String

)

;

published
properties

Text

:

String

read

FText

write

DoIt;

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

7 z 12

2009-03-14 15:46

background image

end;

Właściwości w klasie musimy poprzedzać słowem kluczowym properties. Powyższy kod oznacza, że właściwość
Text

będzie typu String, a jej odczytanie będzie równoważne z odczytaniem danych ze zmiennej FText.

Wszystko dzięki klauzuli read, po której następuje nazwa zmiennej umieszczonej w sekcji

private

(nie jest

konieczne umieszczenie zmiennej FText w sekcji

public

). Natomiast w przypadku, gdy użytkownik zechce

przypisać jakąś wartość właściwości Text, wywołaprocedurę DoIt. Nowa wartość zostanie przekazana do
procedury DoIt w parametrze Value.

Warto, abyś przyzwyczaił się do takiej konstrukcji w przypadku komponentów, gdyż w przyszłości często
będziemy ją stosowali.

Chcąc uczynić daną właściwość przeznaczoną tylko do zapisu lub tylko do odczytu, wystarczy pominąć jedną z
klauzul ? albo read, albo write.

Istnieje możliwość dodania na samym końcu słowa kluczowego default, które powoduje ustawienie domyślnej
wartości właściwości.

Rodzaje właściwości

Pracując już jakiś czas z Delphi, zapewne zauważyłeś, że nie wszystkie właściwości w Inspektorze Obiektów są
przedstawione tak samo. Niektóre proste właściwości służą jedynie do wpisywania nowej wartości i
odczytywania jej. Z kolei inne właściwości są przedstawione w postaci listy rozwijalnej. Tabela 14.3 przedstawia
różne typy właściwości.

Tabela 14.3. Typy właściwości

Typy
właściwości

Opis

Wyliczeniowa

Właściwość wyliczeniowa prezentowana jest w Inspektorze Obiektów w formie listy
rozwijalnej (łączenie z typem Boolean) ? rysunek 14.4

Zbiorowa

Właściwość zbiorowa (set) jest prezentowana w formie listy rozwijalnej. Wartości w zbiorze
można zmieniać na True lub False, w zależności od tego, czy właściwość przynależy do
zbioru czy też nie (rysunek 14.5)

Obiektowa

Czasami zdarza się, że właściwość danego komponentu jest konkretnym obiektem (klasą).
Tak jest np. z właściwością Lines komponentu TMemo, która jest właściwością typu

TStringList

. Wówczas przy próbie edycji otwierany zostaje nowy edytor

Rysunek 14.4. Właściwość wyliczeniowa

Rysunek 14.5. Właściwość zbiorowa

Zdarzenia

Zdarzenia służą do zaprogramowania określonej reakcji w momencie zajścia jakiegoś wydarzenia (np. kliknięcia
myszą). Podczas projektowania własnych komponentów dość często będziesz zmuszony do przypisywania w
kodzie programu jakiegoś zdarzenia, tzw. procedury zdarzeniowej. Procedura zdarzeniowa musi mieć określone
parametry, zależne od rodzaju zdarzenia. Przykładowo procedura zdarzeniowa dla zdarzenia OnClick musi mieć
parametr Sender typu TObject. Zatem deklaracja takiej procedury będzie wyglądać tak:

private

procedure MyOnClick

(

Sedner:

TObject

)

;

end;
...
procedure TForm1.

Button1Click

(

Sender:

TObject

)

;

var
MyButton : TButton;
begin
MyButton := TButton.

Create

(

Form1

)

;

MyButton.

Parent

:= Form1;

MyButton.

OnClick

:= MyOnClick; // przypisanie procedury zdarzeniowej

end;
...

W przypadku, gdyby procedura MyOnClick nie posiadała parametru Sender, próba kompilacji programu
zakończyłaby się komunikatem o błędzie: [Error] Unit1.pas(32): Incompatible types: 'Parameter lists differ'.

Metody

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

8 z 12

2009-03-14 15:46

background image

Przypominam, że metody to inaczej procedury i funkcje zawarte w klasie. Aby owe metody były (w przypadku
komponentów) widoczne dla użytkownika komponentu, należy umieścić je w sekcji public.

RTTI

Zajmiemy się teraz pojęciem zwanym RTTI (Run Time Type Information), które umożliwia nam dostęp do
informacji na temat właściwości, zdarzeń poszczególnych komponentów ? wszystko podczas działania
skompilowanej aplikacji.

Właściwości obiektu

Funkcje, z których będziemy korzystać, znajdują się w pliku TypInfo.pas ? dodaj więc do listy uses moduł
TypInfo

. W gruncie rzeczy pobieranie listy właściwości danego obiektu jest proste ? wystarczy skorzystać z

funkcji GetPropList. W rzeczywistości okazuje się, że czeka nas wiele pracy z wskaźnikami.

Funkcja GetPropList w module TypInfo jest zadeklarowana następująco:

function GetPropList

(

TypeInfo: PTypeInfo; TypeKinds: TTypeKinds; PropList: PPropList

)

:

Integer

;

Pierwszy parametr tej funkcji może zawierać wskazanie komponentu, którego będzie dotyczyć operacja ? w to
miejsce możemy np. wstawić instrukcję Button1.ClassInfo. Drugi parametr jest pewnego rodzaju filtrem.
Określa, jakie właściwości chcemy wyświetlić. Jest to właściwość typu zbiorowego, zadeklarowana następująco:

type
TTypeKind =

(

tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat,

tkString, tkSet, tkClass, tkMethod, tkWChar, tkLString, tkWString,
tkVariant, tkArray, tkRecord, tkInterface, tkInt64, tkDynArray

)

;

TTypeKinds =

set of TTypeKind;

Możemy podać, jakie właściwości chcemy wyświetlić. Najlepszym rozwiązaniem jest wstawienie jako drugiego
parametru słowa tkProperties, które obejmuje wszystkie właściwości. Podsumowując, wywołanie funkcji
GetPropList może wyglądać tak:

GetPropList

(

btnGet.

ClassInfo

, tkProperties, PropList

)

;

Zakładamy, że ostatni parametr ? PropList ? jest typu PPropList. Z kolei typ PPropList jest zadeklarowany
następująco:

PPropList = ^TPropList;
TPropList =

array

[

0

..

16379

]

of PPropInfo;

A zatem okazuje się, że PPropList jest wskazaniem typu TPropList, który z kolei jest tablicą PPropInfo:

PPropInfo = ^TPropInfo;
TPropInfo =

packed record

PropType: PPTypeInfo;
GetProc:

Pointer

;

SetProc:

Pointer

;

StoredProc:

Pointer

;

Index:

Integer

;

Default:

Longint

;

NameIndex:

SmallInt

;

Name:

ShortString

;

end;

Wiem, wiem, że to wszystko jest zagmatwane ? jeden typ jest wskazaniem drugiego typu itp., ale musisz się
przyzwyczaić, że całe VCL w ten właśnie sposób jest zbudowane. Pełny kod programu został przedstawiony w
listingu 14.1, a program w trakcie działania ? na rysunku 14.6.

Listing 14.1. Pełny kod źródłowy modułu

unit MainFrm;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, ValEdit;

type
TMainForm =

class

(

TForm

)

btnGet: TButton;
vleValue: TValueListEditor;

procedure btnGetClick

(

Sender:

TObject

)

;

private

{ Private declarations }

public

{ Public declarations }

end;

var
MainForm: TMainForm;

implementation

{$R *.dfm}

uses TypInfo;

procedure TMainForm.

btnGetClick

(

Sender:

TObject

)

;

var
PropList : PPropList;
i :

Integer

;

begin

GetMem

(

PropList,

SizeOf

(

PropList^

))

; // zarezerwuj pamięć

try

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

9 z 12

2009-03-14 15:46

background image

// pobierz listę właściwości
GetPropList

(

btnGet.

ClassInfo

, tkProperties, PropList

)

;

for I :=

0

to

High

(

PropList^

)

?

1

do

begin

if

(

PropList^

[

i

]

<>

nil

)

then

vleValue.

InsertRow

(

PropList^

[

i

]

.

Name

, PropList^

[

i

]

.

PropType

^.

Name

,

True

)

end;

finally

FreeMem

(

PropList

)

;

end;

end;

end.

Rysunek 14.6. Właściwości komponentu TButton

Wywołując funkcję GetPropList w ten sposób:

GetPropList

(

btnGet.

ClassInfo

, tkProperties +

[

tkMethod

]

, PropList

)

;

spowodujemy, że pod uwagę zostaną wzięte także metody danego obiektu.

Dokładniejsze informacje o obiekcie

W poprzednim podpunkcie omówiłem zagadnienie związane z pobieraniem informacji na temat właściwości
danego obiektu. Tym razem zajmiemy się pobraniem informacji na temat samego obiektu (nazwa klasy, nazwa
modułu itp.). Możemy to zrobić za pomocą funkcji GetTypeData, która zdefiniowana jest następująco:

function GetTypeData

(

TypeInfo: PTypeInfo

)

: PTypeData;

Funkcję można wywołać np. w ten sposób:

ClassInfo := GetTypeData

(

btnGet.

ClassInfo

)

;

Dzięki temu rekord ClassInfo będzie zawierał informacje na temat komponentu btnGet (typu TButton).
Rekord ClassInfo jest rekordem typu PTypeData, wyglądającym następująco:

PTypeData = ^TTypeData;
TTypeData =

packed record

case TTypeKind of

tkUnknown, tkLString, tkWString, tkVariant:

()

;

tkInteger, tkChar, tkEnumeration, tkSet, tkWChar:

(

OrdType: TOrdType;

case TTypeKind of

tkInteger, tkChar, tkEnumeration, tkWChar:

(

MinValue

:

Longint

;

MaxValue

:

Longint

;

case TTypeKind of

tkInteger, tkChar, tkWChar:

()

;

tkEnumeration:

(

BaseType: PPTypeInfo;
NameList: ShortStringBase

))

;

tkSet:

(

CompType: PPTypeInfo

))

;

tkFloat:

(

FloatType: TFloatType

)

;

tkString:

(

MaxLength:

Byte

)

;

tkClass:

(

ClassType: TClass;
ParentInfo: PPTypeInfo;
PropCount:

SmallInt

;

UnitName: ShortStringBase;
{PropData: TPropData}

)

;

tkMethod:

(

MethodKind: TMethodKind;

ParamCount

:

Byte

;

ParamList:

array

[

0

..

1023

]

of

Char

{ParamList: array[1..ParamCount] of
record
Flags: TParamFlags;

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

10 z 12

2009-03-14 15:46

background image

ParamName: ShortString;
TypeName: ShortString;
end;
ResultType: ShortString}

)

;

tkInterface:

(

IntfParent : PPTypeInfo; { ancestor }
IntfFlags : TIntfFlagsBase;
Guid : TGUID;
IntfUnit : ShortStringBase;
{PropData: TPropData}

)

;

tkInt64:

(

MinInt64Value, MaxInt64Value:

Int64

)

;

end;

Program wykorzystujący powyższy rekord przedstawiony jest na rysunku 14.7. Sam kod źródłowy znajduje się
w listingu 14.2.

Rysunek 14.7. Informacje na temat obiektu TButton

Listing 14.2. Kod źródłowy modułu

unit MainFrm;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, ValEdit;

type
TMainForm =

class

(

TForm

)

btnGet: TButton;
vleValues: TValueListEditor;

procedure btnGetClick

(

Sender:

TObject

)

;

private

{ Private declarations }

public

{ Public declarations }

end;

var
MainForm: TMainForm;

implementation

{$R *.dfm}

uses TypInfo;

procedure TMainForm.

btnGetClick

(

Sender:

TObject

)

;

var
ClassInfo : PTypeData;
begin
ClassInfo := GetTypeData

(

btnGet.

ClassInfo

)

;

vleValues.

InsertRow

(

'Nazwa klasy'

, ClassInfo.

ClassType

.

ClassName

,

True

)

;

vleValues.

InsertRow

(

'Klasa bazowa'

, ClassInfo.

ClassType

.

ClassParent

.

ClassName

,

True

)

;

vleValues.

InsertRow

(

'Moduł'

, ClassInfo.

UnitName

,

True

)

;

vleValues.

InsertRow

(

'Liczba właściwości'

,

IntToStr

(

ClassInfo.

PropCount

)

,

True

)

;

vleValues.

InsertRow

(

'Liczba parametrów'

,

IntToStr

(

ClassInfo.

ParamCount

)

,

True

)

;

vleValues.

InsertRow

(

'Rozmiar'

,

IntToStr

(

btnGet.

InstanceSize

)

,

True

)

;

end;

end.

Podsumowanie

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

11 z 12

2009-03-14 15:46

background image

« Część III

Spis treści

Tworzenie komponentów »

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

W IĘCEJ

»

Delphi
C/C++
Turbo Pascal
Assembler
PHP

Programy
Dokumentacja
Kursy
Komponenty

W IĘCEJ

»

Niniejszy rozdział poświęcony był bardziej teoretycznym zagadnieniom, związanym z komponentami i z
biblioteką VCL. Przybliżyłem w nim budowę samej biblioteki VCL, wspomniałem też o podstawowych klasach, na
których opiera się owa biblioteka. Nie zapomniałem także o CLX. Praktycznym tworzeniem komponentów w
Delphi zajmiemy się w kolejnym rozdziale.

Załączniki:

Listingi_14.zip

(7.88 kB)

Więcej informacji

Delphi 2005. Kompendium
programisty

Adam Boduch

Format: B5, stron: 1048
oprawa twarda
Zawiera CD-ROM

©

Helion 2003. Autor:

Adam Boduch

. Zabrania się rozpowszechniania tego tekstu bez zgody autora.

Kategoria

:

Kompendium

Ostatnia modyfikacja

08-03-2006 14:08

Ostatni autor

Adam Boduch

Ilość wyświetleń

16285

Wersja

1

Marooned

dnia 04-06-2007 14:28

Pojawiło się mnóstwo '?' w kodzie, warto by go poprawić.

tomalla

dnia 28-11-2006 21:03

mam kłopot z funkcją FindComponent.
zrobiłem sobie nową klasę w innym unicie ( jak w tym tekście o klasach w kompendium ).
dodałem wszystkie potrzebne unity w USES - między innymi Classes, a i tak nie rozpoznaje funkcji
FindComponent :?
Undeclared identifier: 'FindComponent'.
Dziwne jest to, że w głównym module ( ten z formami ), ta funkcja jest rozpoznawalna.
POMOCY!!!

Dodaj komentarz

Delphi :: Kompendium :: Rozdział 14 - 4programmers.net

http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_14

12 z 12

2009-03-14 15:46


Wyszukiwarka

Podobne podstrony:
Delphi Kompendium Roz8
Delphi Kompendium Roz10
Delphi Kompendium Roz6
Delphi Kompendium Roz12
Delphi Kompendium Roz5
Delphi 7 Kompendium programisty
Delphi 7 Kompendium programisty del7ko 2
Delphi 7 Kompendium programisty
Delphi Kompendium programisty 2
Delphi Kompendium Roz5
Delphi 7 Kompendium programisty
Delphi 7 Kompendium programisty 2
Delphi Kompendium programisty
Delphi Kompendium Roz6
Delphi Kompendium Roz12
Delphi Kompendium programisty 2
Delphi 7 Kompendium programisty del7ko
Delphi Kompendium programisty delpbb

więcej podobnych podstron