Naučte se efektivně používat C++ Builder - I.

V tomto článku opustíme (alespoň na nějaký čas) konkrétní tématiku tvorby komponent pro C++ Builder a budeme se věnovat problematice programování v prostředí C++ Builder obecněji.
V tomto článku opustíme (alespoň na nějaký čas) konkrétní tématiku tvorby komponent pro C++ Builder a budeme se věnovat problematice programování v prostředí C++ Builder obecněji. Jak z vlastní praxe (školím programování), tak ze sledování různých diskusních fór na Internetu jsem došel k některým nepříliš potěšujícím poznatkům:

Mnoho programátorů (správnější by bylo designérů), kteří začali programovat přímo v C++ Builder (nebo některém podobném RAD vizuálním prostředí, jako např. Delphi či Visual Basic) vůbec nevidí pod povrch (nebo vidí jen málo), čímž mám na mysli především obecné principy programování v prostředí Windows, tedy zjednodušeně ono „nepopulární“ Win32 API, a často ani dost dobře nezná základy jazyka C. To se týká především práce s „céčkovskými řetězci“. Je totiž velice lákavé používat typ AnsiString a nějakými „primitivními“ typy jako char*, LPTSTR apod. se nezabývat. Na první pohled je vše v pořádku, ale v určitých případech dojde na lámání chleba, a pak zjistíte, že v časově náročných operacích, jako například prohledávání velmi dlouhých textových bufferů, je AnsiString je metoda AnsiCompare přibližně 50x pomalejší než strcmp. Podobných příkladů by se našlo více.

C++ Builder svádí s velkému „nadužívání“ komponent se všemi negativními důsledky. Jak už jsem uvedl, mnoho programátorů v C++ Builderu prakticky nezná Win API, a když narazí na problém, který pomocí vizuální VCL nelze vyřešit, jsou pak „ochotni“ třeba dlouhé hodiny hledat na Internetu nějakou komponentu, která problém „elegantně“ vyřeší, ovšem s tím, že s sebou nabalí spoustu kódu, který v tu chvíli programátor vůbec nepotřebuje. Je to asi paradoxní, ale tvůrce komponent většinou komponenty používá nejméně, prostě proto, že si to umí napsat přímo a efektivněji. To mohu potvrdit z vlastní praxe. Komponenty, které jsem dělal na zakázku pro jiné firmy, bych ve vlastní aplikaci nikdy nepoužil. Tím samozřejmě nechci říci, že jsem proti komponentám, ale jejich použití a výběr by měly být uvážlivé.

Jak jsem uvedl v prvním bodě, C++ Builder velice úspěšně skrývá před programátorem základní stavební kameny programů pro Windows. A bohužel tento trend je s novějšími verzemi C++ Builder stále zřetelnější. Příklad? Kdysi, ještě v době Windows 3.x, měl Borland na svoji dobu výborný nástroj Resource Workshop, který umožňoval pracovat se základními stavebními kameny programů pro Windows, jako jsou zdroje (resources), tedy např. ikony, kurzory, bitmapy, dialogy menu a další. Nyní, díky tomu, že ve VCL aplikaci jsou data formuláře ukládána do zdrojů jako obecná data, která jsou „čitelná“ pouze pro VCL aplikaci (o efektivnosti rozkódování textového zápisu vlastností komponent se zde nebudu nyní zmiňovat…), se standardní zdroje staly chudým příbuzným. Jediným nástrojem na editaci zdrojů je ImageEditor, který ovšem v dnešní podobě patří spíše do muzea. Tuším, že jeho první verze se objevila s Delphi 1 (pro Windows 3.x), a od té doby se prakticky nezměnil. Umožňuje editovat pouze ikony, kurzory a bitmapy. Navíc o ikonách v 256 barvách nebo jiné velikosti než 16 či 32 si můžete nechat jen zdát, podobně to platí o kurzorech – o existenci barevných kurzorů Image Editor nemá ani potuchy. A editoru resource skriptů si také v C++ Builder můžeme nechat jen zdát.

A nyní zase trochu optimismu

Ale nyní přeladíme na optimistickou notu. Naštěstí v rukou zkušeného programátora může být i C++ Builder výkonný a efektivní nástroj. Samozřejmě (pokud používáme VCL knihovnu) nikdy nepřekročíme práh, který je dán tím, že platíme daň za rychlý, vizuální vývoj. Můžeme se mu však snažit maximálně přiblížit. A to je také jedním z cílů článků, které budou v tomto seriálu následovat. Samozřejmě (jak doufám) mnoho užitečných tipů a rad zde najdou i ti, kteří nechtějí proniknout pod slupku a mají problémy typu „jak na to?“

Vývojové prostředí

Tolik na úvod. V tomto článku se trochu podíváme na vývojové prostředí.

Instalace

Již při instalaci C++ Builderu na platformě Windows NT/2000 narazíte na pro neznalého nepříjemný problém. Když nainstalujete C++ Builder jako „Administrator“, což by měl být standardní postup, poté se přihlásíte pod nějakým jiným účtem (také standardní postup ve Windows 2000), zjistíte, že na paletě komponent vám většina komponent nebo všechny komponenty chybí. Jak si poradit? Je potřeba pod tímto (a každým dalším) účtem znovu nainstalovat C++ Builder a při instalaci zvolit, že chcete pouze vytvořit nový záznam v registrech, jak vidíte na následujícím obrázku

Po tomto kroku by již pod příslušným účtem mělo být vše v pořádku a budete mít k disposici celou paletu komponent.

Nastavení prostředí a editoru

Nyní několik možná subjektivních doporučení na přizpůsobení vývojového prostředí.

Nejprve se podívejme na volbu „Environment Options“:

Zde naleznete mimo jiné záložku „Preference“. Doporučuji mít zaškrtnutou volbu „Autosave Options – Editor Fines“. Jde o to, že před spuštěním programu (uvnitř IDE) se automaticky uloží provedené změny. Vzhledem k tomu, že díky chybě v programu může dojít k úplnému zatuhnutí celého IDE, můžete v tom případě přijít o provedené změny, pokud jste je neuložili před spuštěním „ručně“. A kdo na to má pokaždé myslet, že?

Ve volbách „Environment Options“ bych ještě doporučil zaškrtnout volbu (pokud není defaultně) „Cache headers on startup“, tedy „kešování“ hlavičkových souborů (nesmíte v nich však mít kód), které poněkud urychlí kompilaci, pokud nemáte extrémně málo RAM paměti. Již při 128 MB je to určitě výhodné a kdo má dnes méně?

Nyní k nastavení „Editor Properties“:

Zde máte možnost (kupodivu) zvolit globální mapování horkých kláves. To je velmi výhodné zejména pro programátory, kteří současně používají Visual C++ (nebo z něj přecházejí). Na záložce „Key Mappings“ si můžete nastavit (mimo jiné) například právě mapování horkých kláves jako v Microsoft Visual Studiu.

Dále k volbě písma a barevnému kódování. Pokud chcete mít na obrazovce zobrazen větší počet řádků – při zachování velikosti a čitelnosti písma, zvolte font Courier (optimální velikost 10) a dále si na záložce „Colors“ zrušte u všech (tuším, že je nastavena 1 nebo 2krát) položek tučné písmo (bold). U rezervovaných slov lze místo tučného černého písma nastavit například normální modré písmo. Hned uvidíte, že budete mít větší přehled (ne každý má fotografickou paměť).

Nyní k nastavení vlastnosti „Code Insight“, tedy mimo jiné doplňování kódu a nabízení parametrů funkcí. Zde si neodpustím poznámku o „dobrém vtipu Borlandu“. Defaultní nastavení 1 sekunda? To snad nemyslí vážně. Předpokládám, že většina programátorů píše více než jedním prstem a ta jedna sekunda je příliš krátká na „přestávku na kafe“ a příliš dlouhá na trpělivost programátora. Druhou, smutnější věcí je, že (alespoň do verze 5, uvidíme ve verzi 6, Delphisté by mohli poreferovat...) je minimální nastavitelná prodleva půl sekundy. Samozřejmě si ihned nastavte alespoň tuto možnost. Ti, kteří jako já na stejném počítači používají současně s C++ Builderem také Visual C++, si jistě již porovnali rychlost a přívětivost této funkce s obdobnou funkcí ve Visual C++, zde nazývanou „Statement comletion“. Dále ponechám bez komentáře.

Ještě se zmíním o možnosti nastavení tabelátoru, kde výchozí hodnota 8 je asi pro většinu programátorů příliš velká. Tuto volbu naleznete hned na první záložce dialogu „Editor Properties“. Dále na záložce „Display“, pokud chcete ušetřit co nejvíce místa na obrazovce, můžete zúžit pruh zobrazovaný na levé straně editoru, kde se zobrazují například značky „breakpointů“ apod. Toto nastavení je na záložce „Display“ jako „Gutter width. Osobně mám nastaveno 15, což plně dostačuje.

Tolik asi k nastavení prostředí. Další volby si jistě každý s tím, jak bude C++ Builder více poznávat, upraví sám.

Nastavení projektu

Častým problémem některých programátorů bývá, jak zařídit, aby jejich program bylo možno spustit „tak jak je“ i na „čistém počítači“, tedy bez nainstalovaných balíčků a dalších runtimových knihoven.

Pokud tedy chcete mít veškerý potřebný kód v jednom exe souboru, musíte vybrat volbu „Project Options“ a na záložce „Packages“ nesmíte mít zaškrtnutou volbu „Build with runtime packages“. Znamená to, že program nebude používat runtimové balíčky, což jsou v podstatě běžné DLL knihovny, pouze mají koncovku BPL. Dále na záložce linker nesmíte mít zaškrtnutou volbu „Use dynamic RTL“, tedy dynamické použití runtimové knihovny.

Výsledkem těchto nastavení je samozřejmě podstatně zvětšený exe soubor, který však můžete spustit kdekoli na „čistých Windows“.

Pro začínající programátory ještě připomenu, že v nastavení „Project Options“ jsou na záložce „Compiler“ 2 tlačítka – „Full debug“ a „Release“. Ta nám jednoduše nastavují 2 „krajní“ možnosti výsledného kódu. Verze Debug je samozřejmě určena výhradně pro ladění, tedy spouštění uvnitř vývojového prostředí (IDE). Obsahuje totiž v sobě vše to, co je potřebné pro ladění programu, jako krokování, definování breakpointů a tak dále. Důsledkem je pochopitelně výrazně větší a pomalejší kód.

Jako poslední nastavení projektu, o kterém se zde zmíním, je záložka „Application“ (opět ve volbě „Project Options“. Zde je možné vybrat ikonu, která bude hlavní ikonou aplikace, tedy tou ikonou, jež se standardně zobrazí v systémové nabídce (vlevo nahoře) formuláře a reprezentuje aplikaci na panelu úloh. Dále tato ikona většinou reprezentuje aplikaci (tedy její exe soubor) v průzkumníku. Napsal jsem většinou. V závěrečné části článku si vše vysvětlíme podrobněji.

A na závěr i trochu praxe

Abychom celý článek nevěnovali pouze „suché“, i když důležité teorii, na závěr uvedu praktické ukázky toho, o čem jsem se již zmínil.

Rychlost AnsiStringu

Na začátku jsem se zmiňoval o rychlosti metod třídy AnsiString. V ukázkové aplikaci je realizováno měření rychlosti porovnání dvou řetězců. V prvním případě pomocí metody AnsiCompare třídy AnsiString, ve druhém WinAPI funkcí lstrcmp, ve třetím „klasickou“ céčkovskou funkcí strcmp. Jak je vše realizováno, vidíte na následujícím výpisu kódu:

#define repeat 5000000

AnsiString as;
LPTSTR lpStr;
char* ch;

void __fastcall OnAnsiString()
{
DWORD dw;
int res;
as = "abcdefghijklmno";
dw = GetTickCount();
for ( int i = 0; i < repeat; i++ )
res = as.AnsiCompare("abcdefg11111111");
dw = GetTickCount() - dw;
ShowMessage(IntToStr((int)dw));
}

void __fastcall OnTCHAR()
{
DWORD dw;
  int res;
lpStr = (LPTSTR)malloc(100*sizeof(TCHAR));
strcpy(lpStr, "abcdefghijklmno");
dw = GetTickCount();
for ( int i = 0; i < repeat; i++ )
res = lstrcmp(lpStr, "abcdefg11111111");
dw = GetTickCount() - dw;
ShowMessage(IntToStr((int)dw));
  free(lpStr);
}

void __fastcall OnChar()
{
  int res;
DWORD dw;
ch = new char[100];
strcpy(ch, "abcdefghijklmno");
dw = GetTickCount();
for ( int i = 0; i < repeat; i++ )
res = strcmp(ch, "abcdefg11111111");
dw = GetTickCount() - dw;
ShowMessage(IntToStr((int)dw));
delete ch;
}

A výsledky. Release verze programu na počítači s Pentiem III / 866 MHz s 512MB RAM dává následující časy v milisekundách:

  • AnsiCompare - 15 743 ms
  • lstrcmp – 7 601 ms
  • strcmp – 190 ms
Rozdíl v čase mezi strcmp a AnsiCompare je tedy přibližně 80násobný. Samozřejmě že ve Windows je doporučeno používat funkci lstrcmp, která mimo jiné automaticky podporuje unicode, pokud je definován, a její algoritmus je odlišný od funkce strcmp. I když bychom tedy „zásadně“ používali tuto funkci, stále máme dvojnásobný rozdíl v rychlosti.

Ikona programu

Nyní trochu podrobněji k problematice ikony aplikace. Ikona, kterou si nastavíte ve (výše zmíněných) volbách projektu, bude zobrazena v systémové nabídce formuláře a bude reprezentovat aplikaci na pruhu úloh. Pro ty znalejší WinAPI: je to ikona, která je nastavena jako ikona třídy okna buď při registraci třídy (prvek hIcon struktury WNDCLASSEX), nebo ji můžeme za běhu změnit pomocí funkce SetClassLongPtr (resp. SetClassLong). Avšak to, která ikona reprezentuje exe soubor například v Průzkumníku Windows, je něco jiného. Systém si vybere ze zdrojů programu ikonu s nejnižším identifikátorem. C++ Builder se opět chová poněkud nestandardně a ukládá ikony do zdrojů v identifikátoru ve tvaru řetězců, což není nejefektivnější, ale nicméně je to povoleno. Pak tedy systém vybere první ikonu podle „abecedního“ řazení. Jako příklad jsem do projektu přidal další soubor zdrojů, nazvaný „extra.res“ a vytvořený ImageEditorem, ve kterém je jedna ikona nazvaná „AAAAAA“. Po překompilování uvidíte, že exe soubor bude v Průzkumníku reprezentovat právě tato ikona a nikoli ikona vybraná ve volbách projektu, kterou IDE standardně nazve „MAINICON“. Pokud si zmíněnou vlastní ikonu přejmenujete na „ZZZZZ“, bude opět v Průzkumníku ikona „MAINICON“.

Příště se mimo jiné ještě vrátíme k tématu ikony a ukážeme si, jak za běhu nastavit ikonu formuláři a aplikaci. Také upozorním na některé chyby v „dokumentaci“, které mohou leckterého programátora řádně potrápit a připravit ho zcela zbytečně o spoustu času.

Ukázkový příklad si můžete stáhnout zde: cb_efektivne_1.zip

Diskuze (14) Další článek: Instalace Windows XP bez bootovatelné CD-ROM

Témata článku: , , , , , , , , , , , , , , , , ,