-
V další aplikaci se budeme zabývat prací se soubory. Z existujícího textového
souboru se pokusíme vytvořit nový soubor s pozměněným obsahem. Program
nazvaný FILTR umí převést všechny znaky textového souboru na velká písmena,
zvětšit jen písmena každého prvního slova ve větě nebo odstranit znaky
z druhé části tabulky ASCII (písmena s háčky a čárkami). Vytvoříme formulář
podle následujícího obrázku (je zde použita komponenta RadioGroup):
Uživatel může zadat názvy vstupního a výstupního souboru ve dvou editačních
ovladačích nebo stisknutím tlačítka Změnit otevřít příslušné dialogové
okno pro výběr souboru. U komponenty OpenDialog nastavíme Options
na [ofPathMustExist, ofFileMustExist] a u SaveDialog na [ofOverwritePrompt,
ofPathMustExist, ofCreatePrompt]. Vlastnosti Filter u obou dialogových
oken nastavíme na Textový soubor (*.txt). Obsluha stisku horního
tlačítka Změnit bude tvořena příkazem (pro spodní tlačítko ji vytvořte
sami):
if (OpenDialog1->Execute())
Edit1->Text = OpenDialog1->FileName;
Do soukromé části deklarace formuláře vložíme tyto deklarace:
FILE *VstSoubor,
*VystSoubor;
int DelkaSouboru;
void __fastcall PrevodVelka();
void __fastcall PrevodPrvniVelk();
void __fastcall PrevodSymb();
Obsluha stisku tlačítka Převést je tvořena příkazy (je zobrazeno
dialogové okno, které bude popisovat proces převodu; tento další formulář
bude obsahovat pouze komponentu ProgressBar a BitBtn s textem
OK;
tlačítko zakážeme a obsluha jeho stisknutí bude tvořena příkazem
Close();):
if ((Edit1->Text
!= "")&&(Edit2->Text != "")) {
if ((VstSoubor
= fopen(Edit1->Text.c_str(), "rt")) == NULL){
ShowMessage("Nelze otevřít vstupní soubor.");
return;
}
fseek(VstSoubor,
0L, SEEK_END);
DelkaSouboru
= ftell(VstSoubor);
fseek(VstSoubor,
0L, SEEK_SET);
if ((VystSoubor
= fopen(Edit2->Text.c_str(), "wt")) == NULL){
ShowMessage("Nelze otevřít výstupní soubor.");
return;
}
Form2->Show();
Form2->BitBtn1->Enabled
= false;
Button3->Enabled
= false;
switch (RadioGroup1->ItemIndex)
{
case 0: PrevodVelka(); break;
case 1: PrevodPrvniVelk(); break;
case 2: PrevodSymb(); break;
}
fclose(VstSoubor);
fclose(VystSoubor);
Form2->BitBtn1->Enabled
= true;
Button3->Enabled
= true;
}
else ShowMessage("Zadej
jména souborů.");
Zbývá ještě vytvořit tři metody provádějící požadovaný převod. Následuje
výpis těchto metod (je zde i pomocná funkce převádějící velká písmena na
malá):
char __fastcall LowCase(char
Zn)
{
if ((Zn >=
'A') && (Zn <= 'Z')){return Zn - 'A' + 'a';}
else return
Zn;
}
void __fastcall TForm1::PrevodVelka()
{
int Pozice
= 0;
while (!feof(VstSoubor))
{
fputc(UpCase(fgetc(VstSoubor)), VystSoubor);
Pozice++;
Form2->ProgressBar1->Position = Pozice * 100 / DelkaSouboru;
Application->ProcessMessages();
}
}
void __fastcall TForm1::PrevodPrvniVelk()
{
int Pozice
= 0;
char Zn;
bool Tecka
= true;
while (!feof(VstSoubor))
{
Zn = fgetc(VstSoubor);
if ((Zn >= 'A') && (Zn <= 'Z')){
if (Tecka) {fputc(Zn, VystSoubor); Tecka = false;}
else {fputc(LowCase(Zn), VystSoubor); Tecka = false;}
}
else if ((Zn >= 'a') && (Zn <= 'z')){
if (Tecka) {fputc(UpCase(Zn), VystSoubor); Tecka = false;}
else {fputc(Zn, VystSoubor); Tecka = false;}
}
else if ((Zn == '.') || (Zn == '?') || (Zn == '!'))
{fputc(Zn, VystSoubor); Tecka = true;}
else {fputc(Zn, VystSoubor);}
Pozice++;
Form2->ProgressBar1->Position = Pozice * 100 / DelkaSouboru;
Application->ProcessMessages();
}
}
void __fastcall TForm1::PrevodSymb()
{
int Pozice
= 0;
int Zn;
while (!feof(VstSoubor))
{
Zn = fgetc(VstSoubor);
if (Zn < 128) fputc(Zn, VystSoubor);
Pozice++;
Form2->ProgressBar1->Position = Pozice * 100 / DelkaSouboru;
Application->ProcessMessages();
}
}
Tím je naše aplikace hotova a můžeme ji vyzkoušet. Pokuste se pochopit
jak pracuje. V aplikaci se pracuje se soubory způsobem používaným v C.
Pokuste se tuto aplikaci změnit tak, aby byly použity souborové datové
proudy.
-
Vedle používání textových souborů můžeme také běžným způsobem používat
binární soubory. Nejprve vytvoříme aplikaci, která bude zobrazovat grafy
(seznámíme se s komponentou Chartfx) a později k této aplikaci přidáme
možnost ukládat a načítat zobrazené hodnoty do a ze souborů. Začneme s
vývojem nové aplikace. Formulář zvětšíme a umístíme na ní komponentu Chartfx
(bude zabírat asi horní dvě třetiny formuláře). Na zbývající plochu formuláře
umístíme ještě komponentu StringGrid (s pěti sloupci a čtyřmi řádky,
bez fixních řádků a sloupců, bez posuvníků a k vlastnosti Options
přidáme hodnotu goEditing), komponentu ComboBox (vlastnost
Style
nastavíme na csDropDownList a prvky seznamu nastavíme na 1 –
Lines, 2 – Bar, 3 – Spline, 4 – Mark, 5 – Pie, 6 – Area, 7 – Pareto, 8
– Scatter a 9 – HiLow) a tlačítko s textem Aktualizuj. Mřížku
řetězců můžeme editovat a aby přijímala pouze celá čísla musíme obsloužit
její událost OnGetEditMask. Tuto obsluhu bude tvořit příkaz:
Value = "!09";
Tím máme možnost zadat do buněk mřížky jednomístné nebo dvojmístné
číslo. Při vytváření formuláře vyplníme mřížku náhodnými hodnotami a voláním
obsluhy stisku tlačítka Aktualizuj tyto hodnoty zobrazíme v grafu.
Do veřejné části deklarace formuláře přidáme:
bool Modifikovano;
AnsiString AktualniSoubor;
Obsluha OnActivate formuláře bude tedy tvořena příkazy:
Randomize();
for (int I = 0; I
< 5; I++)
for (int J
= 0; J < 4; J++)
StringGrid1->Cells[I][J] = IntToStr(random(100));
Button1Click(this);
ComboBox1->ItemIndex
= Chartfx1->ChartType - 1;
Modifikovano = true;
AktualniSoubor =
"";
a obsluhu stisku tlačítka Aktualizuj tvoří příkazy (nápovědu
k používání komponenty Chartfx vyvoláme stiskem F1 při vybrané komponentě;
nápověda je ale určena pro Delphi):
Chartfx1->OpenDataEx(COD_VALUES,5,4);
for (int I = 0; I
< 5; I++){
Chartfx1->ThisSerie
= I;
for (int J
= 0; J < 4; J++)
Chartfx1->Value[J] = StrToIntDef(StringGrid1->Cells[I][J], 0);
}
Chartfx1->CloseData(COD_VALUES);
Modifikovano = true;
Zbývá ještě vytvořit obsluhu události OnChange kombinovaného
ovladače. Tvoří ji příkazy:
Chartfx1->ChartType
= ComboBox1->ItemIndex + 1;
Modifikovano = true;
Tím je tato část aplikace hotova. Vyzkoušejte jak pracuje.
-
Aplikaci vytvořenou v předchozím zadání rozšíříme o možnost ukládání zobrazovaných
dat do souboru. K aplikaci přidáme nabídku Soubor s volbami Otevřít,
Uložit
a Uložit jako (můžete přidat i volbu Konec) a přidáme komponenty
OpenDialog
a SaveDialog (nastavíme vhodně jejich vlastnosti). Obsluha volby
Otevřit
bude tvořena příkazy:
FILE *LoadFile;
if (OpenDialog1->Execute())
{
AktualniSoubor
= OpenDialog1->FileName;
Caption =
"Graf " + AktualniSoubor;
if ((LoadFile
= fopen(AktualniSoubor.c_str(), "rb")) == NULL){
ShowMessage("Nelze otevřít soubor");
return;
}
int Hodnota;
for (int I
= 0; I < 5; I++)
for (int J = 0; J < 4; J++){
fread(&Hodnota, sizeof(Hodnota), 1, LoadFile);
StringGrid1->Cells[I][J] = IntToStr(Hodnota);
}
fread(&Hodnota,
sizeof(Hodnota), 1, LoadFile);
ComboBox1->ItemIndex
= Hodnota;
Modifikovano
= false;
fclose(LoadFile);
ComboBox1Change(this);
Button1Click(this);
}
Zbývající obsluhy vytvořte sami a aplikaci vyzkoušejte. Nahraďte opět
souborové operace C souborovými datovými proudy.
-
V předchozí aplikaci jsme se seznámili s komponentou Chartfx. Nyní
se touto komponentou budeme zabývat podrobněji.
Graf vytváříme stejným způsobem, jako používáme jiné komponenty. Umístíme
komponentu na formulář a nastavíme její inicializační vlastnosti.
Po vytvoření grafu je nutno alespoň specifikovat data, která chceme
zobrazit (zatím jsou zobrazována náhodná data). Pro specifikaci zobrazených
dat musíme použít vlastnost Value, tj. vlastnost, která musí být
použita jako pole vlastností:
Chart1->Value[nPoint] = dValue;
Tento příkaz říká, že hodnota dValue je hodnota bodu nPoint
v sérii určené vlastností ThisSerie. Např. následující příkazy nastavují
bod 3 série 0 na hodnotu 10.5:
Chart1->ThisSerie = 0;
Chart1->Value[3] = 10.5;
Před použitím této vlastnosti je nutno zajistit, že komunikační kanál
ke komponentě je otevřen. To provedeme dvojicí metod OpenDataEx
a CloseData. Kód nastavující data tedy bude vypadat např. takto:
// Otevření kanálu hodnot specifikujícího
2 série a 7 bodů
Chart1->OpenDataEx(COD_VALUES,2, 7);
// Kód nastavující data
Chart1->ThisSerie = 0;
for (int i = 0; i < 7; i++)
Chart1->Value[i] = 9;
Chart1->ThisSerie = 1;
for (int i = 0; i < 7; i++)
Chart1->Value[i] = 15;
// Uzavření kanálu hodnot
Chart1->CloseData(COD_VALUES);
Tímto způsobem se nastavují zobrazovaná data. Můžeme si to nyní vyzkoušet.
Začneme vývoj nové aplikace, na formulář umístíme komponentu ChartFX,
změníme její jméno na Chart1, zvětšíme její velikost tak, aby zabírala
většinu plochy formuláře a vytvoříme obsluhu události OnActivate
formuláře s tímto kódem:
Chart1->OpenDataEx(COD_VALUES,2,8);
Chart1->ThisSerie = 0;
Chart1->Value[0] = 30;
Chart1->Value[1] = 20;
Chart1->Value[2] = 40;
Chart1->Value[3] = 60;
Chart1->Value[4] = 50;
Chart1->Value[5] = 15;
Chart1->Value[6] = 24;
Chart1->Value[7] = 35;
Chart1->ThisSerie = 1;
Chart1->Value[0] = 45;
Chart1->Value[1] = 60;
Chart1->Value[2] = 30;
Chart1->Value[3] = 60;
Chart1->Value[4] = 80;
Chart1->Value[5] = 45;
Chart1->Value[6] = 15;
Chart1->Value[7] = 45;
Chart1->CloseData(COD_VALUES);
Po spuštění aplikace jsou zde zadaná data zobrazena v grafu. Vyzkoušejte.
-
Nyní se budeme zabývat změnou dat zobrazených v grafu v předchozím kroku.
Pro změnu zobrazených hodnot používáme stejné vlastnosti jako pro počáteční
zadávání dat.
Volání OpenDataEx s novým počtem sérií a bodů zruší existující
data a připraví komunikační kanál k přijetí nových dat.
// Otevírá kanál hodnot specifikací 4 sérií
a 8 bodů
// Toto volání zruší existující data
Chart1->OpenDataEx(COD_VALUES,4, 8);
// Kód nastavující data
for (int i = 0; i < 4; i++){
Chart1->ThisSerie = i;
for (int j = 0; j < 8; j++){
Chart1->Value[j] = 12;
}
}
// Uzavření kanálu hodnot
Chart1->CloseData(COD_VALUES);
Pokud pouze chceme změnit hodnoty beze změny počtu bodů nebo sérií,
pak můžeme použít příznak COD_UNCHANGE, který znamená, zachování starých
dat s výjimkou těch, které změníme ve vlastnosti Value:
// Otevírá kanál hodnot se zachováním počtu
sérií a bodů
Chart1->OpenDataEx(COD_VALUES, COD_UNCHANGE,
COD_UNCHANGE);
// Modifikace požadovaného bodu
Chart1->ThisSerie = 1;
Chart1->Value[4] = 10.5;
// Uzavření kanálu hodnot
Chart1->CloseData(COD_VALUES);
Budeme pokračovat ve vývoji aplikace z předchozího bodu. Na formulář
přidáme tlačítko a vytvoříme obsluhu jeho stisknutí kódem:
void __fastcall TForm1::Button1Click(TObject
*Sender)
{
int i;
double d1[8],d2[8];
randomize();
for(i=0; i<7; i++){
d1[i] = random(100);
d2[i] = random(100);
}
NastavNoveHodnoty(d1, d2);
}
Dále vytvoříme soukromou metodu formuláře:
void __fastcall TForm1::NastavNoveHodnoty(double
*d1, double *d2)
{
int i;
Chart1->OpenDataEx(COD_VALUES,2,8);
Chart1->ThisSerie = 0;
for (i=0; i<7; i++)
Chart1->Value[i] = d1[i];
Chart1->ThisSerie = 1;
for (i=0; i<7; i++)
Chart1->Value[i] = d2[i];
Chart1->CloseData(COD_VALUES);
}
Nyní aplikaci můžeme opět vyzkoušet. Vždy při stisku tlačítka se změní
zobrazené hodnoty.
-
Dále se stručně seznámíme s titulky a legendami grafu. Ke změně titulků
grafu nastavíme vlastnost Title s kódem titulku v indexu na nový
řetězec titulku, jak je ukázáno dále:
Chart1->Title[CHART_LEFTTIT] = "Vydaje";
Chart1->Title[CHART_BOTTOMTIT] = "Mesice";
Pro změnu legendy grafu použijeme vlastnost Legend pro jednotlivé
body a vlastnost SerLeg pro jednotlivé série a kód zadávající legendu
může vypadat takto:
Chart1->Legend[0] = "Leden";
Chart1->Legend[1] = "Unor";
Chart1->Legend[2] = "Brezen";
Chart1->Legend[3] = "Duben";
Chart1->SerLeg[0] = "Prijmy";
Chart1->SerLeg[1] = "Vydaje";
Přejdeme opět k naši aplikaci. Přidání titulků a legendy provedeme
přidáním následujícího kódu na závěr obsluhy události OnActivate
formuláře:
Chart1->Title[CHART_LEFTTIT] = "Platby";
Chart1->Title[CHART_BOTTOMTIT] = "Mesice";
Chart1->Legend[0] = "Leden";
Chart1->Legend[1] = "Únor";
Chart1->Legend[2] = "Březen";
Chart1->Legend[3] = "Duben";
Chart1->Legend[4] = "Květen";
Chart1->Legend[5] = "Červen";
Chart1->Legend[6] = "Červene";
Chart1->Legend[7] = "Srpen";
Chart1->SerLeg[0] = "Prod A";
Chart1->SerLeg[1] = "Prod B";
Aplikaci vyzkoušejte.
-
Dále se budeme zabývat změnou vzhledu (změnou vizuálních atributů) grafu.
Komponenta poskytuje 3 režimy zobrazení:
-
režim 2D
-
režim "plochého" 3D
-
režimy 3D (s rotací) nebo prohlížení 3D
Implicitní režim vytváření grafu je režim 2D. Toto můžeme přepsat a nastavit
jako implicitní režim "plochého" 3D při návrhu nebo za běhu aplikace použitím
vlastnosti Chart3D takto:
Chart1->Chart3D = true;
K nastavení režimu prohlížení 3D, musí být graf v režimu "plochého"
3D a provedeme následující volání:
Chart1->Angles3D = MAKELONG(30,60);
Dále se budeme zabývat změnou některých atributů, které definují způsob
zobrazení grafu. Všechny tyto atributy mohou být změněny koncovým uživatelem
prostřednictvím nabídky a svázaných dialogů.
-
Barevné schéma: Popisuje jak graf kreslí označovače (sloupce, body,
kruhové výseče, apod.) a mohou být Solid (plné barvy), BWPatterns
(černobílé vzory) a Patterns (barevné vzory).
-
Rastr: Popisuje vodorovné a svislé čáry kreslené v grafu.
-
Barvy pozadí: Barvy použité k zobrazení různých pozadí v grafu.
V následujícím kódu jsou použity vlastnosti, které umožňují měnit zobrazovací
atributy:
// nastavení barevného schématu
Chart1->Scheme = CHART_CSPATTERN;
// nastavení rastru
Chart1->Grid = CHART_HORZGRID;
// nastavení barev pozadí
Chart1->RGBBk = RGB(0,255,0);
Chart1->RGB2DBk = RGB(200,20,90);
Chart1->RGB3DBk = RGB(200,20,90);
I když graf používá implicitně 8-mi bodové písmo Arial k zobrazení
titulků, legend a dalších textů v grafu a programátor může měnit tato písma
pomocí několika vlastností Font.
Opět se vrátíme k naši aplikaci. Na konec obsluhy události OnActivite
přidáme příkazy:
Chart1->View3D = true;
Chart1->Angles3D = MAKELONG(30,60);
Chart1->Grid = CHART_HORZGRID;
Chart1->RGBBk = RGB(0,255,0);
Chart1->RGB2DBk = RGB(200,20,90);
Chart1->RGB3DBk = RGB(200,20,90);
Vyzkoušejte.
-
Dále se budeme zabývat vytvářením nástrojů a dalších vizuálních prvků v
grafech. Graf dává koncovému uživateli 4 nástroje, které usnadňují změnu
některých charakteristik grafu.
Nástroj (vlastnost) |
Použit k ... |
ToolBar |
Změna typu grafu, rastru apod. |
LegendBar |
Zobrazuje legendu X a sérií. |
PaletteBar |
Mění barvy pomocí techniky tažení. |
PatternBar |
Mění výplňové vzory pomocí techniky tažení. |
Z pohledu programátorů práce těchto nástrojů je plně transparentní a
mohou být zobrazeny během návrhu nebo při běhu aplikace nastavením příslušné
vlastnosti na true.
TChartfx má zabudovaný kód k vytváření a zobrazování stavového
řádku, k informování koncového uživatele o stavu programu. Nejsnadnějším
způsobem vytváření stavového řádku je použití metod OpenDataEx a
CloseData
ve spojení s metodou SetStatusItem.
Následuje příklad kódu vytvářejícího stavový řádek:
// Otevření komunikačního kanálu
Chart1->OpenDataEx(COD_STATUSITEMS,4,0);
// Nastavení prvků
Chart1->SetStatusItem(0,true,IDM_TEXT1,true,100,50,4,CHART_STLEFT);
Chart1->SetStatusItem(1,true,IDM_TEXT2,true,80,80,5,CHART_STCENTER);
Chart1->SetStatusItem(2,false,NULL,true,40,40,10,NULL);
Chart1->SetStatusItem(3,true,IDM_TEXT3,true,50,30,2,CHART_STRIGHT);
// Uzavření kanálu prvků
Chart1->CloseData(COD_STATUSITEMS);
Kód nutný k zobrazení stavového řádku je:
Chart1->ShowStatus = true;
a kód k zadání textu prvku stavového řádku je:
// wIdm je identifikace prvku použitá při
jeho vytváření
Chart1->StatusText[wIdm] = "Nový text";
Použití těchto příkazů pro vytváření nástrojů a ovládání stavového
řádku si ukážeme opět na naši aplikaci. Následující příkazy přidáme opět
na závěr obsluhy událostí OnActivate:
Chart1->OpenDataEx(COD_STATUSITEMS,4,0);
Chart1->SetStatusItem(0, true, 101, true,
100, 50, 4, 0);
Chart1->SetStatusItem(1, true, 102, false,
80, 80, 5, 0);
Chart1->SetStatusItem(2, false, 0, true,
40, 40, 10, 0);
Chart1->SetStatusItem(3, false, 103, true,
50, 30, 4, 0);
Chart1->CloseData(COD_STATUSITEMS);
Chart1->StatusText[101] = "Text 1";
Chart1->StatusText[102] = "Text 2";
Chart1->StatusText[103] = "Text 3";
Chart1->ShowStatus = true;
Chart1->ToolBar = true;
Chart1->PaletteBar = true;
Vyzkoušejte.
-
Dále se budeme zabývat událostmi generovanými grafem a zpracováním těchto
zpráv. Příklady některých událostí generovaných grafem jsou:
Událost |
Nastane když |
LButtonDblClk |
Uživatel dvojitě klikne na některou část grafu. |
RButtonDown |
Uživatel stiskne pravé tlačítko myši na grafem. |
Destroy |
Graf bude zrušen. |
ReadFile |
Má být čten soubor. |
Menu |
Uživatel zvolil uživatelem definovaný prvek nabídky. |
Obsluhy událostí se používají obvyklým způsobem. V naší aplikaci vytvoříme
obsluhu dvojitého klinutí levým tlačítkem myši. Tato obsluha je tvořena
příkazy:
if ((nSerie == -1) || (nPoint == -1))
ShowMessage("Prázdné dvojité kliknutí
X: "+AnsiString(x)+" Y: " + y);
else {
Chart1->ThisSerie = nSerie;
double Hodnota = Chart1->Value[nPoint];
if (Hodnota < 25) nRes = 1;
else
if (Hodnota < 50) Chart1->HText
= "Hodnota mezi 25 a 50";
}
Vyzkoušejte.
Komponenta TChartfx umožňuje provádět ještě mnoho dalších činností.
Nebudeme se jimi již ale zabývat.