-
Kreslení za běhu aplikace si ukážeme ještě na jedné jednoduché aplikaci.
Začneme s vývojem nové aplikace. U formuláře nastavíme vlastnost Color
na clBlack. Na formulář dále přidáme komponentu Timer, kde
Interval
nastavíme na 500. Před deklaraci třídy formuláře do hlavičkového
souboru formuláře umístíme tyto deklarace:
const int MaxPoints
= 15; // Počet kreslených bodů
struct TRPoint {
float X, Y;
};
a do soukromé části deklarace třídy formuláře přidáme:
TRPoint
Points[MaxPoints];
float
Rotation; // v radiánech
int
PointCount;
void __fastcall RotatePoints();
Metoda RotatePoints bude tvořena příkazy:
void __fastcall TForm1::RotatePoints()
{
// Všechny
úhly jsou v radiánech
const float
M_2PI = 2 * M_PI;
float StepAngle
= M_2PI / PointCount;
Rotation +=
M_PI / 32;
if (Rotation
> StepAngle) Rotation -= StepAngle;
int i;
float j;
for (i = 0,
j = Rotation; i < PointCount; i++, j += StepAngle) {
Points[i].X
= cos(j);
Points[i].Y
= sin(j);
}
}
K formuláři vytvoříme obsluhu události OnCreate s příkazy:
Canvas->Pen->Color
= clTeal;
Rotation = 0;
PointCount = MaxPoints;
RotatePoints();
Dále vytvoříme obsluhu OnPaint formuláře. Zde budou příkazy:
int centerX = ClientWidth
/ 2;
int centerY = ClientHeight
/ 2;
int radius = min(centerY,
centerX);
Canvas->Ellipse(0,
0, radius*2, radius*2);
int i,j;
for (i = 0; i <
PointCount; i++) {
for (j = i
+ 1; j < PointCount; j++) {
Canvas->MoveTo(radius
+ floor(Points[i].X * radius),
radius
+ floor(Points[i].Y * radius));
Canvas->LineTo(radius
+ floor(Points[j].X * radius),
radius
+ floor(Points[j].Y * radius));
}
}
Obsluhu OnResize formuláře tvoří příkaz:
Invalidate();
Zbývá ještě vytvořit obsluhu OnTimer časovače. Zde budou příkazy:
RotatePoints();
Invalidate();
Tím je naše aplikace hotova. Vyzkoušejte co dělá a snažte se pochopit
význam jednotlivých metod.
-
Dále se seznámíme s používáním komponenty HeaderControl. Začneme
s vývojem nové aplikace. Na horní okraj formuláře umístíme komponentu HeaderControl
a nastavíme u ní vlastnost Sections na tři sekce s texty Červená,
Zelená
a Modrá (šířku jednotlivých sekcí nastavíme na 125, minimální šířku
na 50, maximální šířku na 250 a zarovnávání na centrování). Na formulář
dále vložíme vedle sebe tři komponenty Shape tak, aby zaplnily šířku
jednotlivých sloupců hlavičky, vlastnost Shape u nich nastavíme
na stEllipse a barvu výplně změníme podle textu v hlavičce. Dále
vytvoříme obsluhu události OnSectionTrack ovladače
HeaderControl,
která bude tvořena příkazy:
Section->Width =
Width;
Shape1->Width = HeaderControl->Sections->Items[0]->Width;
Shape2->Width = HeaderControl->Sections->Items[1]->Width;
Shape2->Left = HeaderControl->Sections->Items[1]->Left;
Shape3->Width = HeaderControl->Sections->Items[2]->Width;
Shape3->Left = HeaderControl->Sections->Items[2]->Left;
Tím je aplikace hotova, můžeme ji vyzkoušet. Myší lze přetahovat dělící
čáry v hlavičce a tím měnit šířku zobrazené elipsy ve sloupci jehož šířku
měníme.
-
V této kapitole se budeme ještě zabývat vytvářením hodin. Na formulář umístíme
komponenty Timer a Panel (panel zvětšíme na celou plochu
formuláře a také zvětšíme písmo jeho titulku). Vytvoříme ještě obsluhu
události OnTimer časovače. Bude tvořena příkazem:
Panel1->Caption =
TimeToStr(Time());
Funkce Time vrací objekt typu TDateTime, který obsahuje
aktuální čas a funkce TimeToStr jej převede na řetězec. Tím jsou
nejjednodušší (digitální) hodiny hotovy. Tvar výpisu je určen nastavením
národnostních zvyklostí ve Windows.
-
V další aplikaci se pokusíme vytvořit analogové hodiny. Formulář, který
potřebujeme pro ručičkové hodiny je ještě jednodušší. Obsahuje pouze časovač.
Většina kódu je v obsluze události OnPaint. Protože potřebujeme
vykreslovat tři různé hodinové ručičky, přidáme do formuláře veřejnou metodu,
kterou budeme kreslit jednotlivé ručičky. Bude to funkce:
void __fastcall TForm1::KresliRucicku(int
XStred, int YStred,
int Polomer, int ZpPolomer, double Uhel)
{
Canvas->MoveTo(XStred-floor(ZpPolomer*cos(Uhel)),
YStred-floor(ZpPolomer*sin(Uhel)));
Canvas->LineTo(XStred+floor(Polomer*cos(Uhel)),
YStred+floor(Polomer*sin(Uhel)));
}
Do deklarace formuláře ještě vložíme následující soukromé položky:
unsigned short int
Hodina, Minuta, Sekunda;
int XStred, YStred,
Polomer;
Obsluha události OnPaint formuláře je tvořena následujícími
příkazy:
double Uhel;
int I, X, Y, Velikost;
XStred = ClientWidth
/ 2;
YStred = ClientHeight
/ 2;
if (XStred > YStred)
Polomer = YStred - 10;
else Polomer = XStred
- 10;
Canvas->Pen->Color
= clYellow;
Canvas->Brush->Color
= clYellow;
Velikost = Polomer
/ 50 + 1;
for (I = 0; I <
12; I++){
Uhel = 2 *
M_PI * (I + 9) / 12;
X = XStred
- floor(Polomer * cos(Uhel));
Y = YStred
- floor(Polomer * sin(Uhel));
Canvas->Ellipse(X-Velikost,
Y-Velikost, X+Velikost, Y+Velikost);
}
Canvas->Pen->Width
= 2;
Canvas->Pen->Color
= clBlue;
Uhel = 2 * M_PI *
(Minuta+45) / 60;
KresliRucicku(XStred,
YStred, Polomer * 90 / 100, 0, Uhel);
Uhel = 2 * M_PI *
(Hodina + 9 + Minuta / 60) / 12;
KresliRucicku(XStred,
YStred, Polomer * 70 / 100, 0, Uhel);
Canvas->Pen->Width
= 1;
Canvas->Pen->Color
= clRed;
Uhel = 2 * M_PI *
(Sekunda + 45) / 60;
KresliRucicku(XStred,
YStred, Polomer, Polomer * 30 / 100, Uhel);
Zbývá ještě vytvořit několik obsluh událostí. Obsluha OnTimer
časovače je tvořena příkazy:
unsigned short SetinySec;
DecodeTime(Time(),
Hodina, Minuta, Sekunda, SetinySec);
Refresh();
Obsluhu OnResize formuláře tvoří příkaz: Refresh();
Jestliže
vytvoříme ještě obsluhu události OnCreate formuláře s následujícím
příkazem, pak hodiny budou ukazovat správný čas ihned od zobrazení.
Timer1Timer(this);
Vytvořte tyto hodiny.
-
Předchozí program sice funguje, ale k dokonalosti mu ještě něco chybí.
Obrázek hodin je nestabilní; příliš bliká. Ve skutečnosti je totiž každou
sekundu celý obsah formuláře vymazán a znovu vykreslen. Pokuste se tento
program vylepšit tak, že smažete pouze starou sekundovou ručičku a potom
ji nakreslete znova na novém místě.
-
Chceme-li uložit informaci o stavu aplikace, abychom ji mohli při dalším
spuštění programu obnovit, můžeme ji uložit do souboru, a to v takovém
formátu, jaký uznáme za vhodný. Nicméně Windows zajišťují explicitní podporu
pro inicializační soubory (s příponou INI). Každá aplikace může mít svůj
vlastní INI soubor a zapisovat do něj řetězce, čísla nebo hodnoty typu
bool.
Stejné hodnoty je možné také číst. Builder obsahuje třídu
TIniFile,
s jejíž pomocí můžeme manipulovat s INI soubory. Vytvoříme objekt této
třídy, přiřadíme mu soubor a můžeme z něj informace jak číst, tak je do
něj zapisovat. Pro vytvoření tohoto objektu je nutné zavolat konstruktor,
kterému předáme jako parametr název souboru.
Existují dvě možnosti umístění INI souboru na disku. Jednak je možné
uložit jej do adresáře aplikace a konstruktoru předat úplnou cestu k němu.
Druhým běžnějším řešením je uložit inicializační soubor do adresáře Windows.
V tomto případě zadáváme pouze název souboru.
INI soubory jsou rozděleny na sekce označené názvem uzavřeným v hranatých
závorkách. Každá sekce obsahuje několik prvků tří možných druhů: řetězec,
celé číslo nebo logická hodnota. Třída TIniFile obsahuje metody
pro čtení každého z těchto typů a jsou zde též metody pro jejich zápis.
V metodách určených ke čtení můžeme specifikovat implicitní hodnotu, která
bude použita v případě, kdy odpovídající záznam v INI souboru neexistuje.
Využití INI souborů si ukážeme v následující aplikaci. Formulář aplikace
je prázdný a jsou zde pouze obsluhy událostí OnCreate a OnClose
formuláře. Do INI souboru budeme ukládat umístění a velikost našeho formuláře
a při dalším spuštění toto umístění a velikost použijeme. Do soukromé části
deklarace formuláře umístíme (do hlavičkového souboru formuláře vložíme
#include
<vcl/inifiles.hpp>):
TIniFile *IniFile;
Obsluha OnCreate je tvořena příkazy:
int Stav;
IniFile = new TIniFile("Project1.ini");
Stav = IniFile->ReadInteger("Form1","Status",
0);
if (Stav != 0) {
Top = IniFile->ReadInteger("Form1","Top",
0);
Left = IniFile->ReadInteger("Form1","Left",
0);
Width = IniFile->ReadInteger("Form1","Width",
0);
Height = IniFile->ReadInteger("Form1","Height",
0);
switch (Stav)
{
case 2: WindowState = wsMinimized; break;
case 3: WindowState = wsMaximized; break;
}
}
a obsluhu OnClose tvoří:
int Stav;
if (Application->MessageBox("Uložit
aktuální stav formuláře?",
"Dotaz", MB_YESNO | MB_ICONQUESTION ) == IDYES) {
switch (WindowState)
{
case wsNormal:
IniFile->WriteInteger("Form1","Top", Top);
IniFile->WriteInteger("Form1","Left", Left);
IniFile->WriteInteger("Form1","Width", Width);
IniFile->WriteInteger("Form1","Height", Height);
Stav = 1;
break;
case wsMinimized: Stav = 2; break;
case wsMaximized: Stav = 3; break;
}
if (!Active)
Stav = 2;
IniFile->WriteInteger("Form1","Status",
Stav);
}
delete IniFile;
Tím je naše aplikace hotova a můžeme ji vyzkoušet. Prohlédněte si také
v nějakém textovém editoru vytvořený INI soubor. Pokuste se pochopit, jak
tato aplikace pracuje.
-
V demonstračních programech firmy Borland je uveden další grafický editor.
Tento editor má samostatnou paletu nástrojů. Aplikaci
si stáhněte, přeložte a vyzkoušejte jak pracuje. Podívejte se jakým
způsobem je vyřešena práce s paletou. Prohlédněte si také, jak jsou vyřešeny
ostatní obsluhy událostí.
-
Další aplikace nás podrobněji seznámí s používáním posuvníku. Aplikaci
si opět stáhněte a vyzkoušejte. Podívejte se na obsluhu události
OnScroll
posuvníku. Můžeme zde zjišťovat, jaká činnost s posuvníkem je prováděna.