-
Další komponentou, kterou se budeme zabývat je komponenta TChart
(na Paletě komponent najdeme další dvě verze této komponenty TDBChart
a TQRChart; tyto verze se používají obdobně, ale zatím je nebudeme
používat). Komponenta opět umožňuje vytvářet grafy. Po umístění této komponenty
na formulář můžeme zahájit vytváření grafu. V místní nabídce komponenty
TChart
zvolíme Edit Chart. Je zobrazen Editor grafu. Nyní již můžeme editovat
graf, definovat a zaplňovat jeho datové série.
Editor grafu vypadá takto:
Stránka Chart (z vnějších stránek) Editoru grafu obsahuje definující
informace pro graf. Jsou různé možnosti definování obecných a specifických
parametrů grafu. Některé parametry nemůžeme zadávat dokud nejsou definované
série dat v grafu. Např. se pokuste modifikovat parametr Title a
uvidíte, že se ihned změní v grafu. Ne ale všechny změny vidíme v grafu
ihned.
Nejprve se tedy budeme zabývat přidáváním sérií. Stiskneme tlačítko
Add
na stránce Series (na vnější stránce Chart). Je zobrazena
galerie typů grafů. Vybereme jeden pro přidání do našeho grafu (později
jej budeme moci změnit, pokud budeme požadovat jiný způsob zobrazení dat)
a stiskneme OK. Typ série je automaticky přidán k našemu grafu.
V Editoru grafu vidíme přidanou novou konfiguraci pro novou sérii.
Po přidání série do grafu jsou také přidány některé náhodné hodnoty,
které jsou zobrazeny v grafu (jsou viditelné pouze při návrhu). Pokud nyní
přeložíme naši aplikaci, pak uvidíme prázdný graf.
Je tedy zapotřebí přidat data k sérii. Tato činnost se liší pro TDBChart
a nebudeme se jí zatím zabývat. Předpokládejme, že na formuláři máme komponentu
TChart
s přidanou sérií. Nyní se pokusíme zaplnit sérii programově. Budeme předpokládat,
že máme sérii Pie (s implicitním jménem Series1). Na formulář
umístíme tlačítko a vytvoříme obsluhu jeho stisknutí s kódem:
Series1->Add(40, "Pencil", clRed);
Series1->Add(60, "Paper", clBlue);
Series1->Add(30, "Ribbon", clGreen);
Popis metody Add a dalších potřebných metod a vlastností je
dostupný v nápovědě. Naši aplikaci se pokusíme spustit a po stisknutí tlačítka
uvidíme zobrazení grafu, kód tedy pracuje.
Během návrhu jsou všechny vlastnosti grafu a sérií dostupné v Inspektoru
objektů nebo v Editoru grafu. Editace sérii nejsnadněji provedeme v Editoru
grafu na stránce Series. Pokuste se provést některé změny a uvidíte,
že se provedené změny automaticky projevují v grafu. Při návrhu není dostupný
náš kód a používají se tedy náhodná data. Abychom zjistili, jak se naše
změny projeví za běhu, musíme aplikaci spustit.
Mnoho věcí můžeme vyřešit vizuálně v Editoru nebo můžeme některé parametry
modifikovat v Inspektoru objektů. Můžeme je také řešit kódem.
Pokuste se modifikovat aplikaci ze 4. a 5. zadání předchozí kapitoly
tak, aby se místo komponenty ChartFX používala komponenta TChart.
Více se touto komponentou nebudeme zabývat.
-
Pro zadávání datumů a časů lze použít komponentu TDateTimePicker.
Vlastnost DateMode určuje režim zobrazení ovladače a vlastnost Kind
určuje zda ovladač bude požíván pro datum nebo čas. Umístěte tuto komponentu
na formulář a vyzkoušejte si její použití.
-
Komponenta TAnimate slouží k přehrávání klipů AVI. Pracuje s nekomprimovanými
soubory AVI nebo klipy komprimované kódováním RLE. Tato komponenta nepodporuje
zvuky u klipů. Následují některé vlastnosti této komponenty:
-
ResHandle je madlo Windows modulu, který obsahuje klip AVI jako
zdroj. Vlastnost nastavujeme za běhu na madlo instance nebo modulu, který
obsahuje animační zdroj. Po nastavení ResHandle nastavíme vlastnost
ResID
nebo ResName k indikaci, který zdroj v určeném modulu je požadovaný
klip.
-
Nastavíme AutoSize na true, pokud velikost ovladače má být
určována přehrávaným klipem.
-
StartFrame a StopFrame specifikují rámce, které zahajují
a končí klip.
-
CommonAVI můžeme nastavit k zobrazování některého obecného klipu
Windows poskytnutého v Shell32.DLL.
-
To zda animace běží je určeno vlastností Active a počet opakování
lze nastavit vlastností Repetitions.
-
Vlastnost Timers umožňuje zobrazovat rámce pomocí časovače. Je to
užitečné pro synchronizaci animační sekvence s ostatními akcemi, jako je
přehrávání zvukové stopy.
Pokuste se tuto komponentu použít v některé aplikaci.
-
Komponenta TSplitter rozděluje klientskou oblast formuláře na části,
které mohou měnit velikost. Tuto komponentu přidáváme na formulář mezi
dva zarovnané ovladače. Spliter je umístěn mezi ovladačem který
je zarovnán s jedním okrajem formuláře a ovladačem, který zaplňuje zbytek
klientské oblasti. Použití si ukážeme v následující aplikaci.
Začneme vývoj nové aplikace. Na formulář umístíme Panel, který
zarovnáme se spodním okrajem formuláře. Dále na formulář přidáme komponentu
TSplitter
u které musíme také nastavit vlastnost Align na
alBottom.
Na formulář přidáme komponentu TDirectoryListBox, u které
vlastnost
Align nastavíme na alLeft, další
komponentu
TSplitter (vlastnost
Align je zde již nastavena
na alLeft). Zbývající plochu formuláře zaplníme komponentou TFileListBox
(Align nastavíme na alClient). Nyní již aplikaci můžeme vyzkoušet.
Spustíme ji a pokusíme se měnit velikosti jednotlivých oblastí formuláře.
-
Další zajímavou oblastí C++ Builderu je podpora souborových proudů. Knihovna
VCL obsahuje abstraktní třídu TStream a její tři potomky: TFileStream,
THandleStream
a TMemoryStream. Pro nahrávání dat ze souboru a ukládání do souboru
můžeme použít dva souborově orientované proudy. THandleStream se
používá v případě, kdy již máme madlo souboru. TFileStream použijeme,
když máme jen jméno souboru. Třetí proudovou třídou je TMemoryStream,
která pracuje s pamětí a nikoli se skutečným souborem. Tato třída však
obsahuje speciální metody pro kopírování svého obsahu do nebo z jiného
proudu, který může být souborovým proudem. Proudy mohou nahradit tradiční
soubory. Jejich velkou výhodou je např. to, že můžeme pracovat s paměťovými
proudy, a potom je uložit do souboru. Tímto způsobem lze zvýšit rychlost
programu intenzivně pracujícího se soubory.
Zvláště důležitou vlastností proudů je jejich schopnost přenášet komponenty.
Všechny třídy knihovny VCL jsou potomci TPersistent, speciální třídy
umožňující ukládání objektů do proudů a obsahují metody pro ukládání a
nahrávání všech vlastností a veřejných položek. Proto mohou všichni potomci
třídy
TComponent ukládat sami sebe do proudu nebo mohou být nahráním
z proudu automaticky vytvořeni. Program k tomu může využívat metod proudu
WriteComponent
a ReadComponent. Proudy v zásadě nevědí nic o čtení nebo zápisu
komponent. Metody tříd TStream jednoduše používají dvě jiné třídy:
TReader
a TWriter, obě potomky třídy TFiler. Objekty
TReader
a TWriter používají proud, ke kterému se vztahují a jsou schopné
mu přidělit speciální značky pro provedení kontroly datového formátu. Objekt
TWriter
může uložit značku komponenty, potom uložit komponentu, všechny její vlastnosti
a všechny komponenty, které obsahuje. Obsahuje metodu WriteRootComponent,
která uloží komponentu předanou jako parametr a také všechny komponenty,
které obsahuje. Podobně třída
TReader obsahuje metodu ReadRootComponent,
která je schopná vytvořit nové objekty s využitím informace o třídách uložených
v proudu. To je možné pod jednou podmínkou: název komponenty musí být aplikací
registrován (funkcí
RegisterClasses).
Vraťme se ale ke konkrétní aplikaci. Začneme vývojem nové aplikace.
Formulář této aplikace je jednoduchý. Na horní okraj formuláře vložíme
komponentu Panel (zrušíme jeho titulek) a na ní vložíme tři voliče
s texty Label, Edit a Button (první z nich nastavíme).
Při kliknutí myší na formuláři, vytvoříme komponentu určenou vybraným voličem.
Před deklaraci typu formuláře vložíme deklaraci výčtového typu
enum Typ {Label,
Edit, ButtonX};
popisující vybraný volič a do soukromé části deklarace formuláře umístíme:
int Citac;
Typ Odkaz;
Vytvořte obsluhy kliknutí na voličích tak, aby v položce Odkaz
byla uložena informace o vybraném voliči. Dále vytvoříme obsluhu OnCreate
formuláře s těmito příkazy:
Odkaz = Label;
Citac = 0;
Po vytvoření obsluhy OnMouseDown formuláře již můžeme aplikaci
vyzkoušet. Tuto obsluhu tvoří příkazy:
TControl *Objekt;
AnsiString Nazev;
switch (Odkaz) {
case Label:
Objekt = new TLabel(this); break;
case Edit:
Objekt = new TEdit(this); break;
case ButtonX:
Objekt = new TButton(this); break;
}
Objekt->Parent =
this;
Objekt->Left = X;
Objekt->Top = Y;
Citac++;
Nazev = String(Objekt->ClassName())
+ IntToStr(Citac);
Nazev.Delete(1, 1);
Objekt->Name = Nazev;
Objekt->Visible =
true;
Klikáním myši na formuláři vytváříme komponenty určené vybraným voličem.
Vyzkoušejte.
-
Této aplikaci dále umožníme ukládání vložených komponent do souboru a jejich
opětovnému nahrání ze souboru. K aplikaci přidáme nabídku Soubor
s volbami: Zrušit, Otevřít, Uložit jako a Konec.
Přidáme také komponenty OpenDialog a SaveDialog (kde nastavíme
vhodné vlastnosti; u našich souborů budeme používat příponu CMP).
Tyto komponenty musíme vložit na již použitou komponentu Panel.
Obsluhu volby Zrušit tvoří příkazy (zrušíme všechny komponenty mimo
komponent vložených na panel):
for (int I = ControlCount-1;
I >= 0; I--)
if (String(Controls[I]->ClassName())
!= "TPanel") Controls[I]->Free();
Citac = 0;
Komponenty ukládané do proudu musíme registrovat a tedy do obsluhy
OnCreate
formuláře přidáme příkazy:
TComponentClass classes[3]
=
{__classid(TEdit), __classid(TLabel), __classid(TButton)};
RegisterClasses(classes,
2);
Vytvoříme ještě obsluhu volby Uložit jako. Tvoří ji příkazy:
if (SaveDialog1->Execute()){
TFileStream
*S;
S = new TFileStream(SaveDialog1->FileName,
fmOpenWrite | fmCreate);
for (int I
= 0; I < ControlCount; I++)
if (String(Controls[I]->ClassName()) != "TPanel")
S->WriteComponent(Controls[I]);
delete S;
}
Obsluhu volby Otevřít tvoří:
if (OpenDialog1->Execute())
{
TFileStream
*S;
TComponent
*Novy;
Zruit1Click(this);
S = new TFileStream(OpenDialog1->FileName,
fmOpenRead);
while (S->Position
< S->Size){
Novy = S->ReadComponent(NULL);
InsertControl(dynamic_cast<TControl *> (Novy));
Citac++;
}
delete S;
}
Zbývající obsluhy vytvořte sami. Aplikaci vyzkoušejte.
-
Ještě se seznámíme s klíčovými slovy C++ přidanými do C++
Builderu pro podporu VCL.
Operátor __classid je používán překladačem pro
generování ukazatele na vtable (tabulka virtuálních metod) pro specifikovanou
třídu. Tento operátor byl také použit v předchozím příkladě. Syntaxe:
__classid(classname)
Např. __classid používáme při registraci editoru
vlastnosti, komponenty nebo třídy a s metodou InheritsFrom třídy
TObject.
Klíčové slovo __closure je používáno k deklarování
speciálního typu ukazatele na metodu. Na rozdíl od normálního ukazatele
na funkci, tento ukazatel obsahuje i ukazatel na objekt. Ve standardním
C++ můžeme přiřadit instanci odvozené třídy ukazateli na základní třídu,
ale nemůžeme přiřadit metodu odvozené třídy ukazateli na metodu základní
třídy. Ukazuje to následující příklad:
class
base
{
public:
void
func(int x);
};
class
derived: public base
{
public:
void
new_func(int i);
};
void
(base::*bptr)(int);
bptr
= &derived::new_func; // nedovoleno
Jazykové rozšíření __closure umožňuje toto v C++
Builderu provést. Closure přiřazuje ukazatel na metodu k ukazateli na instanci
třídy. Ukazatel na instanci třídy je použit jako ukazatel this,
když voláme přiřazenou metodu. Deklarace Closure je stejná jako deklarace
ukazatele na funkci, ale před identifikátorem funkce je uvedeno klíčové
slovo __closure. Např.
struct
MyObject
{
double MemFunc(int);
};
double
func1(MyObject *obj)
{
double ( __closure *myClosure )(int);
// Inicializace Closure.
myClosure = obj -> MemFunc;
// Použití Closure k volání metody.
return myClosure(1);
}
V C++ Builderu jsou Closure používány s událostmi.
Klíčové slovo __property deklaruje v deklaraci
třídy vlastnost. Vlastnosti mohou být deklarovány pouze ve třídách. Pro
pole vlastností, index pole může být libovolného typu. Syntaxe:
<property
declaration> ::=
__property <type> <id> [ <prop dim list> ]="{" <prop attrib
list> "}"
<prop dim list> ::= "[" <type> [ <id> ] "]" [ <prop dim list>
]
<prop attrib list> ::= <prop attrib> [ , <prop attrib list> ]
<prop attrib> ::= read = <data/function id>
<prop attrib> ::= write = <data/function
id>
<prop attrib> ::= stored = <data/function
id>
<prop attrib> ::= stored = <boolean constant>
<prop attrib> ::= default = <constant>
<prop attrib> ::= nodefault
<prop attrib> ::= index = <const int expression>
Vlastnosti mají několik služeb, čímž se odlišují od datových
složek. Vlastnosti mohou mít:
-
Přiřazeny čtecí a zápisové metody.
-
Nastavenu implicitní hodnotu.
-
Být uloženy v souboru formuláře.
-
Rozšiřovat vlastnost definovanou v základní třídě.
Klíčové slovo __published specifikuje, že vlastnosti
v této sekci jsou zobrazeny v Inspektoru objektů. Sekci __published
mohou mít pouze třídy odvozené od TObject. Pravidla viditelnosti
pro zveřejňované složky jsou stejné jako pro veřejné složky. Jediný rozdíl
mezi zveřejňovanými a veřejnými složkami je ten, že u zveřejňovaných složek
jsou generovány informace RTTI. To umožňuje aplikacím dynamické dotazy
na složky, metody a vlastnosti.
-
Několik parametrů klíčového slova __declspec poskytuje
jazykovou podporu pro VCL. Následuje popis těchto parametrů.
Parametr delphiclass je použit pro deklarování
tříd odvozených od TObject. Tyto třídy jsou vytvořeny tak, aby byly
kompatibilní s VCL.
Parametr delphireturn je použit pro deklarování
tříd, které vytváříme v C++ Builderu pro podporu zabudovaných datových
typů a jazykových konstrukcí Object Pascalu, které nejsou přirozené v C++.
To zahrnuje Currency,
AnsiString,
Variant,
TDateTime
a Set. Parametr
delphireturn označuje třídy C++ pro VCL kompatibilní
zpracování volání funkcí (parametry a návratové hodnoty). Tento modifikátor
je zapotřebí, když předáváme strukturu funkci hodnotou mezi Object Pascalem
a C++.
Parametr dynamic je používán pro deklarování dynamických
funkcí. Dynamické funkce se podobají virtuálním, ale jsou jinak uložené.
Parametr hidebase chrání sémantiku programu Object
Pascalu při předávání virtuálních a překrytých funkcí C++ Builderu. V Object
Pascalu, virtuální funkce v základní třídě mohou být zobrazeny v odvozené
třídě jako funkce se stejným jménem, ale mohou být chápány jako kompletně
nové funkce bez explicitního vztahu k předchozí funkci. Překladač používá
makro HIDESBASE, k specifikaci, že tyto typy deklarací funkcí jsou kompletně
samostatné. Např. jestliže základní třída T1 deklaruje virtuální bezparametrickou
funkci func a odvozená třída T2 deklaruje funkci se stejným jménem
a signaturou, pak DCC32 vytváří hlavičkový soubor s následujícím prototypem:
virtual
void T1::func(void);
HIDESBASE
void T2::func(void);
Bez HIDESBASE, sémantika C++ indikuje, že virtuální funkce
T1::func
bude přepsána T2::func.
Parametr package indikuje, že kód definice třídy
bude přeložen do balíčku. Parametr pascalimplementation indikuje,
že kód definice třídy bude implementován v Object Pascalu.