background image

 

Rozdział 19 

Raporty 

Delphi jest nie tylko wielce uzdolnionym„projektantem” formularzy, lecz i w pełni 
profesjonalnym narzędziem do pisania raportów. Jego komponenty 

QuickReport

 oferują pełen zestaw udogodnień raportowych, z pomocą których 

możemy tworzyć nawet najbardziej wyszukane sprawozdania finansowo-
ekonomiczne. Delphi zawiera również niezwykle efektywną  kostkę decyzyjną 
(Decision Cube) - komponent, dzięki któremu budowanie raportów krzyżowych 
staje się drobnostką. A jeśli chcielibyśmy nasze raporty finansowe zilustrować 
wykresami, to i tutaj Delphi jest najwłaściwszym partnerem. Diagramy tego 
rodzaju możemy nawet zintegrować z kostkami decyzyjnymi i utworzyć wykresy 
krzyżowe. A wszystko to można zrobić na moment nawet nie opuszczając 
zintegrowanego środowiska programistycznego Delphi. 

Rodzaje raportów 

W rozdziale tym zbudujemy cztery typy raportów, korzystając z bazy danych 
pracowników (Employee), dostarczanej wraz z Delphi Client/Server. Utworzymy 
prosty raport listowy drukujący tablicę klientów, raport grupowy sortujący tablicę 
klientów według krajów, złożony raport typu „pozycja główna/szczegóły” 
(master/detail), wyszczególniający wartość sprzedaży według klientów, i w końcu 
raport krzyżowy, podsumowujący wartość sprzedaży dla każdego kraju z osobna. 
Narysujemy także diagram kołowy (pie chart), wizualnie ilustrujący udział 
poszczególnych krajów w sprzedaży.  

Baza danych pracowników 

Zaimplementowana w 

InterBase baza danych pracowników dołączona jest 

zarówno do samego systemu InterBase, jak i 

pakietu Delphi w 

wydaniu 

Client/Server. Zawiera ona kilka tablic i wykorzystywana jest jako pomoc do 
podręcznika towarzyszącego systemowi InterBase. Rysunek 19.1 pokazuje 
relacyjny schemat bazy danych pracowników. 

background image

582 

Część IV 

Już w swej „dziewiczej” postaci Delphi zawiera alias BDE o nazwie 

IBLOCAL

specjalnie przeznaczony do współpracy z bazą danych pracowników. My zaś 

IBLOCAL

  użyjemy dla zbudowania raportów i wykresów ilustrujących dane 

zgromadzone w tablicach bazy danych pracowników. 

Listowy raport o klientach 

By rozpocząć konstruowanie Raportu listowego dla bazy pracowników, należy 
wykonać następującą procedurę: 

UWAGA: 

Metody budowania raportów, proponowane w tym rozdziale, nie korzystają 

wbudowanych szablonów QuickReport ze składnicy obiektów Delphi. 

Stwierdziłem bowiem, że są one nieco nieporęczne. Odmiennie niż inne składniki 
karty 

Forms

 w repozytorium obiektów (Object Repository), elementy QuickReport 

nie są w rzeczywistości formularzami - są one „w prostej linii” potomkami 
TQuickReport.  

 

Rysunek 19.1
Schemat bazy 
danych 
pracowników 
Employee. 

background image

 Rozdział 19 Raporty 

583

 

Oznacza to, jeśli w celu zaczęcia nowego raportu skopiujemy któryś z tych 
szablonów i nawet otrzymamy coś, co wydaje się być nowym formularzem, to 
w istocie otrzymamy element leżący gdzieś w połowie drogi między 

TPanel

 

TForm

 ze sporą dawką TQuickReport na dodatek. Skutek jest taki, że 

formularze naszych raportów nie pojawia się we właściwości 

Forms

 komponentu 

Screen

, a to z kolei sprawia, iż dostęp do nich stanie się nieco trudniejszy i nie 

pojawią się one na liście raportów prezentowanej przez aplikację REPORTS, którą 
zbudujemy w dalszej części rozdziału. W sumie można więc stwierdzić,  że jeśli 
chcemy mieć możliwość zmieniania naszych raportów en masse korzystając 

wizualnego dziedziczenia formularzy i 

polimorficznego manipulowania 

z użyciem informacji o 

typie w 

fazie wykonania RTTI (Runtime Type 

Information), to o wiele korzystniej jest tworzyć raporty z pomocą formularzy 
i komponentów 

TQuickReport

, które są od siebie niezależne.  

1. Kliknięciem w 

File\New Application

 rozpocznij nową aplikację, służącą jedynie 

do czasowego pomieszczenia budowanego raportu. 

2. Zmień domyślną wartość 

właściwości 

Name

 formularza na 

CustomerReport

 (zmieni to również właściwość 

Caption

). 

3. Umieść na domyślnym formularzu aplikacji komponent 

TQuickReport

 

i jego właściwość 

ReportTitle

 ustaw na 

Customer List Report

4. Umieść na formularzu komponent 

TQuery

 i zmień jego nazwę  (

Name

) na 

MasterQuery

5. Właściwość 

DatabaseName

 komponentu 

MasterQuery

 ustaw na 

IBLOCAL

. Do właściwości 

SQL

 wpisz następujący kod: 

SELECT * FROM 

CUSTOMER

 

6. Otwórz komponent 

MasterQuery

 klikając dwukrotnie w jego właściwość 

Active

 (serwer InterBase musi przy tym pracować; należy pamiętać też, by 

w odpowiedzi na monit podać właściwą nazwę użytkownika i hasło). 

7. Ustaw właściwość 

DataSet

 komponentu 

QuickRep

 tak, by wskazywała na 

nasz komponent 

MasterQuery

8. Na  komponencie 

QuickRep

 umieść cztery komponenty 

QRBand

Właściwość 

BandType

 pierwszego 

QRBand

 ustaw na 

rbTitle

, drugiego na 

rbColumnHeader

, trzeciego na 

rbDetail

, zaś czwartego na 

rbPageFooter

9.  W sekcji tytułowej raportu umieść komponent 

QRSysData

 i jego właściwości 

Alignment

 nadaj wartość 

alCenter

. Jego właściwość 

Data

 ustaw na 

qrsReportTitle

background image

584 

Część IV 

10. W sekcji szczegółów raportu umieść cztery komponenty 

QRDBText

 i ustaw 

ich właściwości 

DataSet

 na 

MasterQuery

. Komponenty te stanowić będą 

kolumny raportu. Przypomnijmy, że by wybrać więcej niż jeden komponent na 
raz, należy go kliknąć przy wciśniętym klawiszu SHIFT.  

11. Właściwość 

DataField

 pierwszego 

QRDBText

 ustaw na 

CUSTOMER

drugiego na 

CITY

, trzeciego na 

STATE_PROVINCE

, a 

czwartego na 

COUNTRY

12. W  sekcji  nagłówków kolumn umieść cztery komponenty 

QRLabel

. Posłużą 

one jako nagłówki kolumn dla listowanych w raporcie pól bazy danych. Każdy 
z nich  umieść nad inną kontrolką 

QRDBText

, zaś ich napis (

Caption

zmodyfikuj tak, by opisywał to pole bazy danych, które identyfikuje. Na 
przykład, 

Caption

 pierwszego komponentu 

QRLabel

 powinien być 

Customer

, ponieważ listować będzie pole 

CUSTOMER

.  

13. Właściwość 

Font

 wszystkich czterech komponentów 

QRLabel

 zmień tak, by 

obejmowała zarówno atrybut 

fsBold

, jak i 

fsUnderline

. Pomoże to 

uwydatnić je w raporcie jako nagłówki kolumn. 

14. W lewym górnym rogu raportu umieść 

QRLabel

 i jego 

Caption

 ustaw na 

Report Date:

.  

15. Bezpośrednio pod etykietą daty raportu dodaj nowy 

QRLabel

 i ustaw jego 

Caption

 na 

Report Time:

.  

16. Po prawej stronie etykiety z datą raportu umieść komponent 

QRSysData

 

i jego  właściwość 

Data

 ustaw na 

qrsDate

. Komponent 

QRSysData

 jest 

specjalnie przeznaczony do podawania wartości zmiennych z 

poziomu 

systemu, takich jak bieżący numer strony, tytuł raportu i temu podobnych. 
Tutaj użyjemy go do wydrukowania bieżącej daty w obszarze tytułowym 
raportu. 

17. Drugi  komponent 

QRSysData

 dodaj po prawej stronie etykiety czasu raportu. 

Jego pole 

Data

 powinno mieć wartość domyślną 

grsTime

. Spowoduje to 

włączenie do nagłówka raportu godziny jego wydrukowania.  

18. Moduł z kodem źródłowym nowego formularza zapisz jako 

LISTREPO.PAS

Po wykonaniu wszystkich tych czynności listowy raport o 

klientach jest 

w zasadzie gotowy. Na rysunku 19.2 pokazano, jak powinien wyglądać ukończony 
projekt. 

background image

 Rozdział 19 Raporty 

585

 

Można łatwo podejrzeć, jak nasz nowy raport wyglądać będzie w fazie wykonania 
(run-time), klikając go prawym klawiszem myszy i wybierając 

Preview

 z menu 

kontekstowego. Taki właśnie widok raportu pokazano na rysunku 19.3. 

Szczęśliwe ukończenie raportu listowego przygotowało nas do przejścia do raportu 
grupowego. Gdy zbudujemy już wszystkie raporty, zobaczymy też, jak 
skonstruować aplikację  służącą do ich uruchamiania. Teraz zamknijmy okno 
podglądu raportu i powróćmy do edytora formularzy Delphi. 

Grupowy raport o klientach 

Pracując nad innymi raportami z tego rozdziału zaoszczędzimy sobie mnóstwo 
czasu i wysiłku, jeśli nasz gotowy raport listowy zapamiętamy w składnicy 

 

Rysunek 19.2
Wygląd 
ukończonego 
listowego raportu 
o klientach. 

 

Rysunek 19.3. 
Listowy raport 
o klientach 
pokazany tak, jak 
będzie wyglądał 
w fazie wykonania. 

background image

586 

Część IV 

obiektów i 

przy tworzeniu wszystkich pozostałych skorzystamy z 

cechy 

dziedziczenia. Wypróbujmy wpierw, jak działa to w przypadku grupowego raportu 
o klientach.  

1.  Prawym klawiszem myszy kliknij utworzony właśnie raport listowy i wybierz 

opcję menu kontekstowego 

Add To Repository

.  

2.  Nowej pozycji w składnicy nadaj jakiś znaczący tytuł, na przykład 

Customer 

Report

, a jako jej opis (

Description

) wpisz 

Generic Customer 

Report Class

. Nowy formularz przypisz do karty 

Forms

 składnicy, po 

czym kliknij klawisz 

OK

.  

3. Kliknij opcję menu 

File\New\Forms

, po czym z okna dialogowego 

New Items

 

wybierz formularz 

Customer Report

4. Zaznacz przycisk opcji 

Inherit

 i kliknij 

OK

. W edytorze formularzy Delphi 

powinien pojawić się nowy formularz 

Customer Report

.  

Zauważmy,  że w naszym nowym formularzu raportu występują już wszystkie 
nagłówki, specyfikacje zbiorów danych (DataSet) i 

inne detale raportów 

z oryginalnego raportu o klientach. Występujące w Delphi wizualne dziedziczenie 
formularzy zaoszczędzi nam trudu pracowitego rekonstruowania wszystkich 
podstawowych elementów w każdym z raportów oddzielnie. 

Mając już nowy formularz na ekranie, możemy od razu przystąpić do takiego 
modyfikowania jego formy, by uzyskać raport grupowy. Tak więc, by utworzyć 
Grupowy raport o klientach, należy wykonać następujące czynności: 

1. Zmień nazwę (

Name

) nowego formularza na 

CustomerGroupReport

2. Właściwość 

ReportTitle

 komponentu 

QuickReport

 zmień na coś 

innego, na przykład na 

Customer Group Report

3. Umieść w raporcie komponent 

TQRGroup

 i jego właściwość 

Master

 ustaw 

tak, by wskazywała na komponent 

QuickRep

. Jego właściwość 

Expression

 ustaw na 

MasterQuery.Country

4. Na  komponencie 

QRGroup

 umieść komponent 

QRExpr

 i 

ustaw jego 

właściwość 

Expression

 na 

MasterQuery.Country

5. Właściwość 

Font

 komponentu 

QRExpr

 zmodyfikuj tak, by obejmowała 

atrybut 

Bold

 i zwiększ wielkość czcionki do 12 punktów, by wyróżniała się na 

wydruku raportu. 

6. Zamknij  komponent 

MasterQuery

, jeśli jest aktualnie otwarty (jego 

właściwość 

Active

 ustaw na 

False

). 

background image

 Rozdział 19 Raporty 

587

 

7. Wywołaj edytor właściwości 

SQL

 i dodaj na końcu istniejącej instrukcji 

SELECT

 klauzulę 

ORDER BY Country

. Po zakończeniu redagowania 

instrukcja 

SELECT

 powinna mieć postać: 

 

SELECT * FROM CUSTOMER ORDER BY Country

8. Otwórz komponent 

MasterQuery

 zmieniając jego właściwość 

Active

 na 

True

Nasz nowy raport jest już gotowy. Moduł  źródłowy naszego formularza 
zapisujemy na dysku jako 

GRPREPO

.

PAS

, po czym klikamy go prawym 

klawiszem myszy i wybieramy opcję 

Preview

. Na rysunku 19.4 pokazano, co 

powinniśmy wtedy zobaczyć. 

Zauważmy, że lista klientów jest teraz zorganizowana według krajów. Ten sposób 
grupowania znany jest jako podział na poziomie grupy (level break) lub 
przerywanie sterowania (control break). Stosowanie w raportach grup pozwala 
sumować dane szczegółowe raportu na każdym poziomie grupowania. Możemy na 
przykład utworzyć stopkę grupy, która podawałaby całkowitą ilość klientów dla 
każdego kraju. Grupy mogą zawierać zarówno nagłówki, jak i stopki, te zaś mogą 
używać pól obliczanych, systemowych lub zwykłych. 

 

Rysunek 19.4. 
Widok grupowego 
raportu o klientach 
w podglądzie. 

background image

588 

Część IV 

UWAGA: 

Zauważmy,  że zmieniliśmy SQL towarzyszący raportowi tak, by zbiór jego 
rezultatów był posortowany według kolumny 

Country

. Jeśli mamy zamiar 

grupować według określonego pola, to należy bezwzględnie zapewnić, by nasz 
zbiór danych był właściwie posortowany. Gdyby tak nie było, to otrzymalibyśmy 
wiele oddzielnych podziałów w różnych miejscach raportu. Jeśli nasz raport ma 
kilka poziomów podziału, to dane należy koniecznie posortować według 
wszystkich uczestniczących w nich pól, i to w takiej samej kolejności, jak 
kolejność odpowiadających im grup w raporcie. 

Raport typu „pozycja główna/szczegóły” 

Kolejnym raportem, który zbudujemy, jest raport typu „pozycja główna/szczegóły” 
(master/detail) o wartości sprzedaży w rozbiciu na poszczególnych klientów. 
Wymienia on po kolei wszystkich klientów i dla każdego z nich podaje 
odpowiadającą mu sumę sprzedaży. By sporządzić nowy raport typu pozycja 
główna/szczegóły, należy wykonać następującą procedurę: 

1. Utwórz nowego potomka oryginalnego raportu o 

klientach korzystając 

z sekwencji opcji 

File\New\Forms\Customer

 

Report\Inherit\OK

.  

2. Właściwości 

Name

 nowego formularza nadaj wartość 

CustomerMDReport

3. Zmień  właściwość 

ReportTitle

 komponentu 

QuickRep

 na 

Sales by 

Customer Report

4. Umieść na formularzu komponent 

TDataSource

 i 

jego właściwość 

DataSet

 zmień tak, by odwoływała się do komponentu 

MasterQuery

5. Umieść na formularzu komponent 

TQuery

 i ustaw jego właściwość 

DatabaseName

 na 

IBLOCAL

. Do jego właściwości 

SQL

 wpisz następujący 

kod: 

SELECT * FROM SALES WHERE Cust_No = :Cust_No 
ORDER BY Order_Date

 

6. Jego właściwość 

DataSource

 zmień tak, by wskazywała na komponent 

TDataSource

, dodany wcześniej. Ustanowi to zależność typu pozycja 

główna/szczegóły pomiędzy tablicą 

CUSTOMER

 (skojarzoną z komponentem 

MasterQuery

) i naszym nowym zapytaniem do tablicy 

SALES

7. Otwórz komponent 

TQuery

, przełączając jego właściwość 

Active

 na 

True

8. Umieść na raporcie komponent 

TQRSubDetail

 i jego właściwość 

Master

 

ustaw tak, by odwoływała się do komponentu 

TQuickRep

. Jego właściwość 

DataSet

 powinna odwoływać się do nowego 

TQuery

background image

 Rozdział 19 Raporty 

589

 

9. Na komponencie 

TQRSubDetail

 umieść trzy komponenty 

TQRLabel

 i trzy 

komponenty 

TQRDBText

. Właściwość 

DataSet

 wszystkich trzech 

komponentów 

TQRDBText

 ustaw na dodany właśnie 

TQuery

10. Właściwość 

DataField

 pierwszego komponentu 

QRDBText

 ustaw na 

OrderDate

, drugiego na 

Discount

, a trzeciego na 

Total_Value

11. W polu 

Mask

 komponentu 

QRDBText

 dla dyskonta (Discount) wpisz 

.#0

zaś w 

polu 

Mask

 analogicznego komponentu dla Total_Value umieść 

#,##0.00

. Właściwość 

Mask

 formatuje liczby pokazywane przez te 

komponenty. W przypadku pola Discount są to wartości zmiennoprzecinkowe, 
zatem przy pomocy maski ograniczamy ilość podawanych przez niego liczb 
znaczących. W przypadku kolumny 

Total_Value

 mamy do czynienia 

z dużymi sumami pieniędzy i tak też pole to formatujemy. 

UWAGA: 

By nasza aplikacja mogła poprawnie manipulować numerycznymi i dziesiętnymi 
polami InterBase’u (takimi jak kolumna 

Total_Value

), będziemy musieli 

właściwość 

Enable BCD

 aliasu IBLOCAL ustawić na 

True

. Jeśli tego nie 

zrobimy, to BDE i w konsekwencji Delphi będą pola tych typów traktować jako 
wartości całkowite. Wskutek tego nasze raporty nie będą w stanie wyświetlać 
części ułamkowych, zaś komponenty edycyjne, takie jak DBEdit, będą odrzucać 
części ułamkowe we wprowadzanych danych. Więcej informacji na ten temat 
znajdziemy w rozdziale 17, „Delphi a InterBase”. 

12. Komponenty 

QRLabel

 umieść ponad każdym z komponentów 

QRDBText

 

w taki sposób, by stały się one nagłówkami dla ich kolumn. Właściwość 

Caption

 każdego 

QRLabel

 zmień tak, by odpowiadała kolumnie, którą 

określa. 

13. Właściwość 

Font

 każdego z 

trzech komponentów 

QRLabel

 w 

sekcji 

QRSubDetail

 zmodyfikuj tak, by zawierała atrybut 

Bold

 

Italic

, co 

pozwoli lepiej uwidocznić etykiety na raporcie. 

W tym momencie nasz nowy raport jest zasadniczo ukończony. Rysunek 19.5 
pokazuje, jak powinien on wyglądać w edytorze formularzy Delphi. 

background image

590 

Część IV 

Teraz moduł naszego formularza zapisujemy jako 

MDREPO.PAS

, następnie zaś 

sam raport klikamy prawym klawiszem myszy i, aby go „podglądnąć”, wybieramy 
opcję 

Preview

. Rysunek 19.6 ilustruje rzeczywisty wygląd naszego nowego raportu 

pozycja główna/szczegóły.  

WSKAZÓWKA: 

Pisząc ten rozdział odkryłem coś, co wygląda na błąd (bug) w komponentach 

QuickReport

 Delphi. Gdy próbowałem po raz pierwszy uruchomić raport typu 

pozycja główna/szczegóły, otrzymałem komunikat Access Violation. Wspominał 
on coś o pustym wskaźniku. Po powrocie z edytora formularzy spostrzegłem,  że 
szerokość komponentu 

TQRDBText

 dla pola 

Order_Date

 zwężyła się do zera 

pikseli. Wszelkie próby poszerzenia go zawiodły, z pewnością więc problem 
dotyczył tego właśnie pola. Skasowałem i ponownie dodałem odpowiedni 
komponent, nadal bez skutku. W końcu zdecydowałem się bezpośrednio dodawać 
komponenty 

TField

 do pól zapytania, klikając dwukrotnie 

TQuery

 dla 

SALES

 

i naciskając CTRL+A. I to z jakiś powodów rozwiązało problem. Jeśli Czytelnik 
popadnie kiedyś w podobne kłopoty, to podana tu wskazówka zaoszczędzi mu 
może nieco frustracji. 
Jeśli w komponentach 

QuickReport

 natkniemy się na nasze „własne” błędy, nie 

zawadzi złożyć wizyty na poświeconej QuickReport stronie WWW pod 

http:// 

www.qusoft.com

. Prócz tego Delphi posiada plik o nazwie 

QRPT2MAN.DOC

 

(znajdujący się w katalogu 

\Program Files\Delphi 3\Quickrpt

), 

zawierający dodatkowe informacje na temat stosowania komponentów 
QuickReport w aplikacjach Delphi. 

 

Rysunek 19.5. 
Nasz raport typu 
pozycja 
główna/szczegóły 
w edytorze 
formularzy Delphi. 

background image

 Rozdział 19 Raporty 

591

 

Nasz raport pozycja/szczegół jest teraz w pełni ukończony. Zamykamy okno 
podglądu i powracamy do edytora formularzy Delphi. 

Raport krzyżowy 

Ze wszystkich rodzajów raportów, omawianych w tym rozdziale, raport krzyżowy 
- który właśnie zamierzamy skonstruować - jest najbardziej niekonwencjonalny. 
Wynika to stad, że nie korzysta on z komponentów 

QuickReport

, a zamiast 

nich używa komponentów typu 

DecisionCube

. Oznacza to w praktyce, że dla 

wydrukowania raportu nie wywołujemy metody drukowania związanej z danym 
komponentem, tak jak to zrobilibyśmy w 

przypadku komponentów 

QuickReport

 - tutaj konieczne będzie wywołanie metody drukowania 

Print

 

formularza.  

Aby skonstruować nasz raport krzyżowy, wykonajmy po kolei poniższe kroki: 

Zainicjuj nowy formularz i 

zmień jego nazwę  (

Name) na 

Customer CTReport

.

 

1.  Na nowym formularzu umieść trzy komponenty 

TPanel

. Właściwość 

Align

 

pierwszego ustaw na 

alTop

, drugiego na 

alBottom

, zaś trzeciego na 

alClient

.  

2. Wykasuj właściwość 

Caption

 drugiego i trzeciego panelu.  

3. Nagłówek, czyli 

Caption

, pierwszego 

TPanel

 ustaw na 

Sales by 

Country and Year

, a jego czcionkę  (

Font

) na 

Arial

 

18 punktowy 

normalny.  

 

Rysunek 19.6. 
Nasz nowy raport 
pozycja 
główna/szczegóły 
w całej swej 
okazałości. 

background image

592 

Część IV 

4.  Na formularzu umieść komponent 

DecisionQuery

 (znajdujący się w karcie 

DecisionCube

 palety komponentów) i jego właściwości 

DatabaseName

 

nadaj wartość 

IBLOCAL

5.  W podobny sposób umieść na formularzu komponent 

DecisionCube

 i jego 

atrybut 

DataSet

 ustaw na dodany właśnie komponent 

DecisionQuery

6.  Dodaj do formularza komponent 

DecisionSource

 i ustaw jego właściwość 

DecisionCube

 na zainstalowany w 

poprzednim kroku komponent 

DecisionCube

7. Komponent 

DecisionGrid

 umieść na trzecim panelu 

TPanel

 (który 

powinien zajmować większą część środkowej części formularza) i ustaw jego 
właściwość 

Align

 na 

alClient

8. Właściwość 

DecisionSource

 komponentu 

DecisionGrid

 ustaw na 

dodany właśnie 

DecisionSource

9.  Na drugim panelu 

TPanel

 (który powinien znajdować się u dołu formularza) 

umieść komponent 

DecisionPivot

 i nadaj jego właściwości 

Align

 

wartość 

alClient

.  

10. Właściwość 

DecisionSource

 komponentu 

DecisionPivot

 ustaw na 

znajdujący się na formularzu komponent 

DecisionSource

11. Komponent 

DecisionQuery

 kliknij prawym klawiszem myszy i z menu 

kontekstowego wybierz edytor zapytań decyzyjnych, czyli Decision  Query 
Editor

12. W  wyświetlonym oknie dialogowym wybierz przycisk 

Query Builder

13. Po  wyświetleniu przez wizualny edytor zapytań  (Visual Query Builder) okna 

dialogowego 

Add

 

Table

, dodaj do zapytania tablice CUSTOMER i SALES, 

klikając je dwukrotnie, po czym kliknij 

Close

14. Pole 

Cust_No

 przeciągnij z tablicy CUSTOMER do kolumny 

Cust_No

 

w tablicy SALES

ustanawiając miedzy nimi złączenie. 

15. Przeciągnij kolumnę 

Country

 z tablicy CUSTOMER do dolnego panelu 

w wizualnym edytorze zapytań, dodając go tym samym do tworzonego raportu. 

16. Prócz tego do zapytania kolumny dodaj 

Order_Date

 i 

Total_Value

 

z tablicy SALES, przeciągając je do dolnego panelu edytora zapytań, po czym 
zakończ edycję klikając przycisk 

OK

 (ten z obrazkiem znaczka „

”). 

17. Powróciwszy do edytora zapytań decyzyjnych, przeciągnij kolumny 

Country

 

Order_Date

 do pola listy 

Dimensions

. Kolumnę 

Total_Value

 

przeciągnij zaś do pola listy 

Summaries

. Na zapytanie o rodzaj agregacji 

należy odpowiedzieć wybraniem opcji 

sum

. Jej wybranie sprawi, że kolumna 

background image

 Rozdział 19 Raporty 

593

 

Total_Value

  będzie sumowana. Po zakończeniu redagowania pole 

Query

 

Text

 na karcie SQL Query powinno wyświetlać następujący kod: 

  SELECT CUSTOMER.COUNTRY, SALES.ORDER_DATE, 

 SUM( SALES.TOTAL_VALUE )  

  FROM CUSTOMER CUSTOMER  
  INNER JOIN SALES SALES  
  ON (CUSTOMER.CUST_NO = SALES.CUST_NO)  

 

GROUP BY CUSTOMER.COUNTRY, SALES.ORDER_DATE

 

 

 Jeśli tak nie jest, to oznacza to, że coś nie wyszło albo w samym oknie 

dialogowym 

Decision

 

Query

 

Editor

, albo w wizualnym edytorze zapytań. 

18. Jeśli kod SQL jest poprawny, kliknij przycisk 

OK

 aby zamknąć edytor zapytań 

decyzyjnych.  

19. Prawym klawiszem myszy kliknij komponent 

DecisionCube

 i wybierz 

opcję edytora kostki decyzyjnej, czyli 

Decision

 

Cube

 

Editor

. Zaznacz kolumnę 

SUM i jej właściwość 

Format

 ustaw na 

#,##0.00

. Zapewni to, że sumy dla 

kolumny 

Total_Value

 wyświetlane będą poprawnie. Wyjdź z 

okna 

dialogowego klikając 

OK

20. Właściwość 

Active

 komponentu 

DecisionQuery

 przestaw na 

True

Powinieneś wtedy ujrzeć, jak twoja siatka decyzyjna (

DecisionGrid

wypełnia się danymi. Jeśli zostaniesz poproszony o 

podanie nazwy 

użytkownika i hasła, to tak jak poprzednio wpisz poprawne wartości. Rysunek 
19.7 pokazuje, jak wszystko to powinno w rzeczywistości wyglądać. 

21. Na zakończenie zapisz moduł swego formularza jako CTREPO.PAS

.

 

Rysunek 19.7
Nasz raport 
krzyżowy tak, jak 
wygląda w trakcie 
projektowania. 

background image

594 

Część IV 

Konstruowanie aplikacji dla raportów 

By właściwie ocenić skuteczność, z jaką komponent 

DecisionCube

 tworzy 

raporty krzyżowe, trzeba zobaczyć go w „akcji”, czyli w fazie wykonania. Tu 
jednak wyłania się kolejne zagadnienie, związane z 

pisaniem raportów - 

konstruowanie aplikacji użytkownika dla raportów.  

Wydruki 19.1 do 19.3 pokazują kod źródłowy programu REPORTS. Aplikacja ta 
korzysta ze wszystkich raportów, które zbudowaliśmy w tym rozdziale (dla 
zwięzłości ich kodu tutaj nie zamieszczono), i pozwala wyświetlać je na 
podglądzie i uruchamiać z jednego centralnego formularza. 

UWAGA: 

By zbudować aplikację REPORTS, należy albo wpisać ręcznie jej kod źródłowy 
wylistowany tutaj, albo też załadować go z płyty CD-ROM-u dołączonej do 
książki. 

Listing 19.1 Kod źródłowy Reports.DPR

-plik projektu Reports 

program reports; 

uses 
 Forms, 
 

repo00 in 'repo00.pas' {Form1}, 

 

listrepo in 'listrepo.pas' {CustomerReport}, 

 

grprepo in 'grprepo.pas' {CustomerGroupReport}, 

 

mdrepo in 'mdrepo.pas' {CustomerMDReport}, 

 

ctrepo in 'ctrepo.pas' {CustomerCTReport}, 

 

salegrap in 'salegrap.pas' {CustomerGraphReport}; 

{$R *.RES} 

begin 
 Application.Initialize; 
 Application.CreateForm(TForm1, 

Form1); 

 Application.CreateForm(TCustomerReport, 

 

 

CustomerReport); 

 Application.CreateForm(TCustomerGroupReport, 

 

 

CustomerGroupReport); 

 Application.CreateForm(TCustomerMDReport, 

 

 

CustomerMDReport); 

 Application.CreateForm(TCustomerCTReport, 

 

CustomerCTReport); 

 Application.CreateForm(TCustomerGraphReport, 

 

CustomerGraphReport); 

 Application.Run; 

background image

 Rozdział 19 Raporty 

595

 

end. 

Listing 19.2 Kod źródłowy repo00.PAS 

-

 formularz główny 

aplikacji 

unit repo00; 

interface 

uses 
 

Windows, Messages, SysUtils, Classes, Graphics, 

 

Controls, Forms, Dialogs,StdCtrls;QuickRpt 

type 
 

TForm1 = class(TForm) 

 btPreview: 

TButton; 

 btPrint: 

TButton; 

 ListBox1: 

TListBox; 

 btCustomerCTPreview: 

TButton; 

 btCustomerCTPrint: 

TButton; 

 Label1: 

TLabel; 

 Label2: 

TLabel; 

 

procedure btPreviewClick(Sender: TObject); 

 

procedure FormShow(Sender: TObject); 

 

procedure btPrintClick( Sender: TObject); 

 

procedure btCustomerCTPreviewClick(Sender: TObject); 

 

procedure btCustomerCTPrintClick(Sender: TObject); 

 private 
 

{ Private declarations } 

 public 
 

{ Public declarations } 

 end; 

var 
 Form1: 

TForm1; 

implementation 

uses listrepo, ctrepo; 

{$R *.DFM} 

procedure TForm1.btPreviewClick(Sender: TObject); 
var 
c,f : Integer; 
begin 
 

if (ListBox1.ItemIndex<>-1) then 

 

 

With Screen do 

 

 

 

For f:=0 to FormCount - 1 do 

 

   With 

Forms[f] 

do 

 

 

 

 

 

For c:=0 to ComponentCount - do 

background image

596 

Część IV 

 

     if(Components[c] 

is 

TQuickRep) 

and 

 

     (TQuickRep(Components[c]).ReportTitle 

 

 

 

 

 

 

 

=ListBox1. Items[ListBox1.ItemIndex]) 

 

     then 

begin 

 

     TQuickRep(Components[c]).Preview; 

 

     break; 

 

     end; 

end; 

procedure TForm1.FormShow(Sender: TObject); 
var 
c,f : Integer; 
begin 
 

With Screen do 

 

 

For f:=0 to FormCount - 1 do 

 

 

 

With Forms[f] do 

 

 

 

 

For c:0 to ComponentCount - 1 do 

 

 

 

 

 

if Components[c] is TQuickRep then 

 

    ListBox1.Items.Add(TQuickRep 

 

 

 

 

 

 

 (Components[c]).ReportTitle); 

 

If (ListBox1.Items.Count <> 0) then ListBox1.ItemIndex:=0; 

end; 

procedure TForm1.btPrintClick(Sender: TObject); 
var 
c,f : Integer; 
begin 
 

if (ListBox1.ItemIndex<>-1) then 

 

 

With Screen do 

 

 

 

For f:=0 to FormCount - 1 do 

 

   With 

Forms[f] 

do 

 

 

 

 

 

For c:=0 to ComponentCount - 1 do 

 

     if 

(Components[c] 

is 

TQuickRep) 

and 

 

     (TQuickRep(Components[c].ReportTitle 

 

 

 

 

 

 

 

=ListBox1.Items[ListBox1.ItemIndex]  

 

     then 

begin 

 

     TQuickRep(Components[c]).Print; 

 

     break; 

 

     end; 

end; 

procedure TForm1.btCustomerCTPreviewClick(Sender: TObject); 
begin 
 CustomerCTReport.Show; 
end; 

procedure TForm1.btCustomerCTPrintClick(Sender: TObject); 
begin 
 CustomerCTReport.Print; 
end; 

background image

 Rozdział 19 Raporty 

597

 

end. 

 

Listing 19.3 Kod źródłowy formularza związanego z

 formularzem 

głównym aplikacji

 

object Form1: TForm1 
 Left=200 
 Top=109 
 Width=544 
 Height=375 
 Caption=’Reports’ 
 Font.Charset=DEFAULT_CHARSET 
 Font.Color=clWindowText 
 Font.Height=-11 
 

Font.Name=’MS Sans Serif’ 

 Font.Style=[] 
 OnShow=FormShow 
 PixelsPerInch=96 
 TextHeight=13 
 objectLabel1: 

TLabel 

   Left=0 
   Top=40 
   Width=79 
   Height=13 
 

 

Caption=’Sales by Country’ 

 end 
 objectLabel2: 

TLabel 

   Left=0 
   Top=120 
   Width=34 
   Height=13 
   Caption=’Others:’ 
 end 
 

object btPreview: TButton 

   Left=0 
   Top=288 
   Width=75 
   Height=25 
   Caption=’Pre&view’ 
   TabOrder=0 
   OnClick=btPreviewClick 
 end 
 

object btPrint: TButton 

   Left=96 
   Top=288 
   Width=75 
   Height=25 
   Caption=’&Print’ 
   TabOrder=1 
   OnClick=btPrintClick 
 end 

background image

598 

Część IV 

 

object ListBox1: TListBox 

   Left=0 
   Top=136 
   Width=169 
   Height=137 
   ItemHeight=13 
   TabOrder=2 
 end 
 

object btCustomerCTPreview: TButton 

   Left=0 
   Top=56 
   Width=75 
   Height=25 
   Caption=’Preview’ 
   TabOrder=3 
   OnClick=btCustomerCTPreviewClick 
 end 
 

object btCustomerCTPrint: TButton 

   Left=88 
   Top=56 
   Width=75 
   Height=25 
   Caption=’&Print’ 
   TabOrder=4 
   OnClick=btCustomerCTPrintClick 
 end 
end 

Na rysunku 19.8 pokazano, jak nowa aplikacja wygląda w fazie wykonania. 

W aplikacji REPORTS zastosowano kilka technik, które być może Czytelnik 
zechce wykorzystać we własnym zakresie. Po pierwsze, rzućmy okiem na kod 
związany ze zdarzeniem 

OnShow

 formularza głównego:  

procedure TForm1.FormShow(Sender: TObject); 
var 

 

Rysunek 19.8. 
Aplikacja 
REPORTS w całej 
swej okazałości 

background image

 Rozdział 19 Raporty 

599

 

 

c, f : Integer; 

begin 
 

With Screen do 

 

 

For f := 0 to FormCount - 1 do 

 

 

 

With Forms[f] do 

 

 

 

 

For c := 0 to ComponentCount - 1 do 

 

 

 

 

 

if Components[c] is TQuickRep then 

 

 

 

 

 

 

ListBox1.Items.Add(TQuickRep    

 

 

 

 

 

 

 

(Components[c]).ReportTitle); 

 

If (ListBox1.Items.Count <> 0) then ListBox1.ItemIndex := 

 

 0; 

end; 

Zacytowany fragment kodu korzysta z predefiniowanej zmiennej 

Screen

 po to, 

by przejrzeć przez wszystkie istniejące formularze i określić, który z nich zawiera 
komponenty 

TQuickRep

. Te formularze, które komponenty 

TQuickRep

 

zawierają, dodawane są do listy kontrolki 

ListBox1

 formularza. Pamiętamy 

oczywiście,  że 

TCustomerReport

 zawiera komponent 

TQuickRep

 i stanowi 

podstawę dla wszystkich innych formularzy raportów w tym rozdziale. 

Po zbudowaniu listy skontrolowana zostaje liczba jej pozycji (

count

). Ma to na 

celu sprawdzenie, czy w ogóle odnaleziono jakieś komponenty 

TQuickRep

. Jeśli 

komponenty takie istnieją  (

Count <> 0

), to w 

ListBox

 wyróżniona zostaje 

pierwsza pozycja listy. 

Interesującym aspektem omawianego kodu jest to, że przy tworzeniu dynamicznej 
listy dostępnych raportów korzysta on informacji o typach fazy wykonania (RTTI, 
Runtime Type Information). Jeśli tylko nasze raporty budujemy jako formularze 
zawierające komponenty 

QuickRep

, możemy postąpić identycznie w naszych 

własnych aplikacjach.  

Teraz przyjrzyjmy się kodowi obsługującemu zdarzenie 

OnClick

 przycisku 

Preview

procedure TForm1.btPreviewClick(Sender: TObject); 
var  
 

c, f : Integer; 

begin 
 

if (ListBox1.ItemIndex <> -1) then 

 

 

With Screen do 

 

 

 

For i := 0 to FormCount - 1 

 

   With 

Forms[f] 

do 

 

 

 

 

 

For c := 0 to ComponentCount - 1 do 

 

 

 

 

 

 

if (Components[c] is TQuickRep) and  

 

     (TQuickRep(Components[c]).ReportTitle 

 

 

 

 

 

 

ListBox1.Items[ListBox1.ItemIndex])  

 

     then 

begin 

 

     TQuickRep(Components[c].Preview; 

background image

600 

Część IV 

 

     break; 

 

     end; 

end; 

Także i 

tutaj kod przebiega w 

pętli poprzez listę dostępnych formularzy 

i komponentów,  poszukując odpowiednika raportu aktualnie wybranego 
w komponencie 

ListBox

. Jeśli znajdzie odpowiadający mu komponent, 

przekształca jego typ na formularz TQuickRep i wywołuje metodę 

Preview

Podobnie jak poprzednio pozwala to wykonywać raporty dynamicznie. Pozwala 
także na dodawanie raportów do aplikacji i sprawia, że możliwe jest ich 
natychmiastowe wykonanie bez żadnego dodatkowego kodowania. Kluczem do 
wszystkiego jest przeglądanie list formularzy i komponentów z pomocą RTTI. 

Wygląd raportów w fazie wykonania 

Ponieważ dla naszych raportów dysponujemy już całkiem niezłą aplikacją, 
możemy przyjrzeć się dokładniej raportowi krzyżowemu. Kliknijmy przycisk 

Preview

 umieszczony poniżej etykiety 

Sales

 

by

 

Country

. Na rysunku 19.9 

pokazano, co powinniśmy zobaczyć:  

Teraz mamy okazje przekonać się, jak potężnym narzędziem jest komponent 

DecisionCube

. W tym celu spróbujemy wykonać następujące czynności: 

1. Przeciągnijmy nagłówek kolumny 

Order_Date

 do nagłówka kolumny 

Country

. Zobaczymy, że odpowiadające im rzędy i kolumny zamieniają się 

 

Rysunek 19.9. 
Nasz raport 
krzyżowy w fazie 
wykonania. 

background image

 Rozdział 19 Raporty 

601

 

miejscami w siatce. Nosi to nazwę „rotacji” (pivoting) i jest jednym z głównych 
powodów, dla których ludzie używają kostek decyzyjnych (zwanych także 
tablicami rotacyjnymi (pivot tables)).  

2. Zwolnijmy  przycisk 

Order_Date

 lub 

Customer

 na komponencie 

DecisionPivot

 u dołu formularza. Przyciski te wskazują, które wymiary 

występują w kostce. Domyślnie uwzględnione są wszystkie, lecz można to 
zmienić w fazie wykonania używając kontrolki 

DecisionPivot

3.  Kliknij prawym klawiszem myszy przycisk

 Order_Date

 lub 

Customer

 i z menu 

kontekstowego wybierz opcję 

Drilled

 

In

. Następnie ten sam przycisk kliknij 

lewym klawiszem myszy, wyświetlając listę możliwych wartości głębszego 
poziomu (drill-in). Można na przykład zagłębić się w kolumnę 

Order_Data

 

i ograniczyć wyświetlane dane do konkretnego roku. Można również zagłębić 
się w kolumnę 

Country

 i przeglądnąć dane dla poszczególnych krajów.  

Wykresy  

Delphi nie tylko pozwala budować wyszukane raporty, lecz i dostarcza narzędzi 
graficznych do kreślenia wykresów i 

diagramów. Komponenty 

DBChart

QRChart

 i 

DecisionGraph

 przeznaczone są specjalnie do konstruowania 

wykresów skojarzonych z danymi (data-aware). Pokażemy teraz, jak komponenty 
te można wykorzystać w budowie skomplikowanych diagramów ekonomiczno-
finansowych. 

Kreślenie za pomocą QRChart 

Zacznijmy od zbudowania prostego diagramu z pomocą należącego do zestawu 

QuickReport

 komponentu 

QRChart

. Dlatego właśnie,  że jest on 

komponentem związanym z 

QuickReport

, można dodawać go do raportów oraz 

podglądać i drukować z użyciem wbudowanych w 

TQuickRep

 metod 

Preview

 

Print

. By utworzyć raport z diagramem, trzeba wykonać następujące kroki: 

1. Z utworzonego wcześniej formularza CustomerReport sporządź nowy 

formularz potomny i nazwij go 

CustomerGraphReport

2. Kliknij komponent 

TQuickRep

 i jego właściwości 

ReportTitle

 nadaj 

wartość 

Graph of Sales by Country

3.  Wybierz wszystkie cztery komponenty 

QRLabel

 z sekcji nagłówków kolumn 

raportu i skasuj zawartość ich atrybutu 

Caption

. Wizualnie będzie to miało 

efekt równoważny do usunięcia ich z raportu. Nie możemy ich zwyczajnie 
usunąć, ponieważ zostały one odziedziczone z innego formularza. 

background image

602 

Część IV 

4. W sekcji szczegółów raportu wybierz wszystkie cztery komponenty 

QRDBText

, wyzeruj ich właściwość 

DataField

, a właściwość 

Width

 

ustaw na 

0

. Będzie to wyglądać tak, jakby zostały usunięte z raportu. 

5. Wybierz jednocześnie sekcje stopki strony, szczegółów i nagłówków kolumn, 

po czym ustaw ich właściwość 

Enabled

 na 

False

. Ich właściwość 

Height

 

zmień natomiast na 

0

. Wizualnie będzie to wyglądać na usuniecie ich 

z raportu. 

6. Powiększ sekcję tytułu tak, by zajmowała przynajmniej połowę formularza. 

Tutaj właśnie zostanie umieszczony wykres, najlepiej więc zapewnić sobie 
dużo wolnego miejsca. 

7. Umieść w obszarze tytułowym komponent 

QRChart

 i tak zwiększ jego 

wymiary, by zajął jak największą część obszaru tytułu. 

8.  Zamknij komponent MasterQuery, a jego SQL zmień następująco:

 

  SELECT C.COUNTRY, SUM(S.TOTAL_VALUE) 

FROM SALES S, 
CUSTOMER C 
WHERE S.CUST_NO=C.CUST_NO 

 

GROUP BY C.COUNTRY 

9. Teraz otwórz go ponownie ustawiając 

Active

 z powrotem na 

True

Zapytanie to zwraca listę krajów z tabeli CUSTOMER wraz z całkowitą 
wartością sprzedaży do każdego z nich, pobraną z tabeli SALES. Nasz nowy 
wykres bazować będzie na tym właśnie zapytaniu. 

10. Dwukrotnie kliknij komponent 

QRChart

, po czym na karcie 

Chart

\

Series

 

kliknij przycisk 

Add

11. Jako typ diagramu wybierz 

Pie

 i kliknij 

OK

12. Na  karcie 

Chart

 kliknij fiszkę 

Titles

 i jako tytuł diagramu wpisz 

Country 

Sales Figures

13. Kliknij  fiszkę 

Series

 (tę na prawo od zakładki 

Chart

), a następnie na karcie 

Series

 kliknij fiszkę karty 

DataSource

14. Na karcie 

DataSource

 wybierz 

DataSet

 jako typ źródła danych dla diagramu. 

Kliknij listę rozwijaną 

DataSet

 i jako zbiór danych (dataset) dla diagramu 

wybierz twój komponent 

MasterQuery

15. Zmień  właściwość 

Labels

 tak, by odnosiła się do kolumny 

Country

 

zapytania; zmodyfikuj też  właściwość 

Pie

, która ma wskazywać na kolumnę 

SUM. Spowoduje to, że rozmiary segmentów koła bazować będą na kolumnie 
SUM, natomiast ilość segmentów zależeć  będzie od kolumny 

Country

Każdy segment reprezentować będzie wartość sprzedaży do innego kraju. 

background image

 Rozdział 19 Raporty 

603

 

W tym momencie nasz prosty diagram kołowy jest już prawie ukończony. Na 
zakończenie klikamy przycisk 

Close

. Rysunek 19.10 przedstawia nasz nowy 

wykres. 

Ponieważ wykres jest już gotowy, moduł jego kodu źródłowego zapamiętujemy 
jako 

SALEGRAP.PAS

. Następnie uruchamiamy aplikację 

REPORTS

 naciskając 

klawisz F9. Gdy aplikacja pojawi się na ekranie, nasz raport z diagramem 
wybieramy z listy raportów i klikamy przycisk 

Preview

. Na rysunku 19.11 

pokazano, co powinniśmy ujrzeć. 

Gdy tylko skończymy podziwiać dziewiczą urodę naszego dzieła, zamykamy 
zarówno okno podglądu, jak i samą aplikację, i powracamy do Delphi. 

 

Rysunek 19.10. 
Nowy wykres 
w formie, w jakiej 
wyświetlany jest 
w edytorze 
formularzy Delphi. 

 

Rysunek 19.11. 
Nasz wykres 
w formie, w jakiej 
widać go na 
podglądzie 
w aplikacji 
RAPORTS. 

background image

604 

Część IV 

Kreślenie przy pomocy DecisionGraph 

Komponentu 

DecisionGraph

 możemy użyć do zobrazowania sum krzyżowych 

generowanych przez komponent 

DecisionCube

. My zaś 

DecisionGraph

 

dodamy do formularza 

CustomerCTReport

, skonstruowanego wcześniej. 

Skorzystamy przy tym z komponentów 

DecisionCube

 istniejących już na 

formularzu. 

By do formularza 

CustomerCTReport

 dodać nowy wykres tego rodzaju, 

należy wykonać następujące czynności: 

1. Naciśnij SHIFT+F12 i załaduj 

CustomerCTReport

, wybierając go z listy 

formularzy. 

2. Właściwość 

Align

 komponentu 

DecisionGrid

 zmień na 

alTop

 i podnieś 

jego dolną krawędź tak, by zajmował on jedynie około połowy wolnego 
miejsca w środkowej części formularza. 

3. W  niezajętej strefie formularza, zwolnionej właśnie przez komponent 

DecisionGrid

, umieść komponent 

DecisionGraph

 i 

ustaw jego 

właściwość 

Align

 na 

alClient

. Powinien wówczas zająć resztę wolnego 

miejsca na formularzu. 

4. Jego 

DecisionSource

 ustaw na znajdujący się na formularzu komponent 

DecisionSource

. Bezpośrednio po tym powinien wyświetlić się nowy 

wykres słupkowy. 

5. Zmodyfikuj nowy wykres, klikając go dwukrotnie, a następnie w edytorze 

klikając fiszkę 

Titles

. Tytuł  (

Title

) wykresu zmień na 

Sales by 

Country and Year

, po czym kliknij 

Close

Nasz nowy wykres jest już gotowy. Jako etykiet dla osi X i słupków używa on krawędzi 
swego komponentu 

DecisionCube

. Pola SUM kostki używa jako osi Y. 

Zobaczmy teraz, jak nowy wykres wygląda w fazie wykonania. Zapiszmy naszą 
pracę, uruchommy aplikację REPORTS i kliknijmy przycisk 

Preview

 dla raportu 

Sales by Country. Rysunek 19.12 pokazuje, co powinniśmy wtedy zobaczyć. 

background image

 Rozdział 19 Raporty 

605

 

By przekonać się, jak ściśle powiązane są ze sobą nasze komponenty 

DecisionGrid

 i 

DecisionGraph

, przeciągnijmy w 

komponencie 

DecisionPivot

 kolumnę 

Order_Date

 ponad kolumną 

Country

 i upuśćmy 

ją z jej prawej strony. Będzie to miało taki skutek, że kolumny zamienia się 
miejscami (na co wskazuje kursor myszy), co z kolei „przekręci” tabelę. 
Zauważmy, że gdy obracamy 

DecisionCube

, zmianie ulega zarówno tabela, jak 

i wykres - tak jak to pokazano na rysunku 19.13. 

Nasz nowy wykres jest teraz w pełni ukończony. Wychodzimy z aplikacji 

REPORTS

 i powracamy do Delphi. 

Wzbogacanie raportów 

Ponieważ pamiętaliśmy, by możliwie wiele naszych raportów oprzeć na wspólnym 
„przodku”, wzbogacenie ich en masse jest już tylko drobnostką. Wykorzystując 

 

Rysunek 19.12. 
Nasz nowy 
DecisionGraph 
w fazie wykonania. 

 

Rysunek 19.13. 
Komponent 

DecisionPivot

 

może obracać 
zarówno 

DecisionGrid

,

 

jak 

DecisionGraph

background image

606 

Część IV 

okoliczność,  że wszystkie one wywodzą się z klasy 

CustomerReport

, do 

obszaru tytułowego każdego raportu dodamy systemową nazwę  użytkownika 
osoby, generującej raport. 

Aby na naszych raportach umieścić pole z nazwą  użytkownika, trzeba wykonać 
następujące kroki: 

1. Załaduj 

CustomerReport

 z powrotem do edytora formularzy Delphi. 

2. Dwa komponenty 

QRLabel

 umieść po prawej stronie obszaru tytułowego 

jednej linii z 

datą wydruku raportu. Pierwszy z 

nich nazwij 

UserNameLabel

, drugi 

laUserName

. Ponieważ komponenty te zostaną 

odziedziczone przez inne formularze, muszą mieć unikalne nazwy wśród 
wszystkich formularzy hierarchii. Zakładanie,  że domyślne nazwy nadawane 
przez Delphi na jednym formularzu nie będą w konflikcie z takimiż nazwami na 
innych, nie jest bynajmniej bezpieczne. 

3.  Kontrolki te umieść obok siebie, przy czym prawa kontrolka powinna kończyć 

się na prawym marginesie raportu. 

4. Ustaw 

Caption

 etykiety 

UserNameLabel

 na 

User Name:

. Właściwość 

Alignment

 etykiety 

laUserName

 ustaw na 

taRightJustify

5. 

Dwukrotnie kliknij zdarzenie 

OnPrint

 komponentu 

laUserName

 

i w następujący sposób zmodyfikuj procedurę obsługi zdarzenia:

 

procedurę TListReport.laUserNamePrint(sender: TObject; var 

Value: String); 
var 
 

MaxNameLen : Integer; 

begin 
 

MaxNameLen := 30; 

 SetLength(Value, 

MaxNameLen); 

 GetUserName(PChar(Value), 

MaxNameLen); 

 SetLength(Value, 

Pred(MaxNameLen)); 

 

 

//Nazwa powraca jako łańcuch zakończony zerem

 

 end; 

Podprogram ten, by nadać wartość przekazanemu mu parametrowi 

Value

wywołuje procedurę API Windowsa o nazwie 

GetUserName

. To, co zostanie 

umieszczone w 

Value

, zostanie wydrukowane w raporcie. Należy zwrócić uwagę 

na konwersję typu (typecasting), konieczną dla przekazania 

Value

 do procedury 

jako łańcucha w stylu C. Po powrocie z 

GetUserName

 zmienna 

MaxNameLen

 

(w której 

GetUserName

 umieścił ilość bajtów przekopiowanych do 

Value

zostaje użyta do nastawienia długości 

Value

 przed powrotem z kodu obsługi 

zdarzenia. Jest to w istocie środek zabezpieczający służący zapewnieniu, że 
łańcuch będzie poprawnie zakończony. 

background image

 Rozdział 19 Raporty 

607

 

By ujrzeć efekt naszych modyfikacji, uruchamiamy ponownie aplikację 

REPORTS

 

i wchodzimy do podglądu niektórych z raportów, opartych na 

Customer 

Report

,. Zobaczymy, że z wyjątkiem raportu krzyżowego, każdy z nich ma teraz 

pole użytkownika w prawym górnym rogu. Choć dodaliśmy je tylko jeden raz 
w jednym miejscu, to zmiana ta przeniosła się na wszystkie formularze potomne. 
Wyobraźmy sobie, ile pracy można by zaoszczędzić, gdyby wszyscy programiści 
aplikacji Delphi projektowali systemy w pełni korzystające z tej niezwykle 
efektywnej właściwości. Na rysunku 19.14 widzimy nasz Raport listowy 
o klientach z dodanym nowym polem. 

 

Rysunek 19.14. 
Dzięki 
dziedziczeniu 
formularzy można 
daleko sięgających 
zmian dokonać 
w przysłowiową 
sekundę.