Dříve než se budeme zabývat dalšími databázovými komponentami, seznámíme
se s vytvářením přezdívek BDE. U našich příkladů jsme se zatím přezdívkám
BDE vyhnuli. Při dalším seznamování s databázovými aplikacemi je ale již
budeme potřebovat. Přezdívku lze vytvořit několika způsoby:
pomocí Administrátora BDE,
pomocí programu Database Desktop,
pomocí průzkumníka SQL (pouze ve verzi Client/Server C++ Builderu) a
pomocí kódu za běhu aplikace.
Nyní se budeme zabývat pouze první z těchto možností.
Při vývoji aplikace je obvykle zapotřebí vytvořit jednu nebo více přezdívek
BDE. Administrátora BDE spustíme volbou Programs | Borland C++ Builder
3 | BDE Administrator. V okně administrátora je uveden seznam nadefinovaných
přezdívek. Je možno zde měnit parametry přezdívek a také vytvářet přezdívky
nové. Prohlédněte si, jaké přezdívky jsou nadefinované.
V dalších zadáních se pokusíme připojit ke cvičné databázi Sybase SQL
Anywhere. Ukážeme si tedy jak vytvořit potřebnou přezdívku pro tuto databázi.
Budeme ale postupovat jiným způsobem.
Nejdříve je nutno překopírovat soubor této cvičné databáze do adresáře
C:\PRAC. Jedná se o soubor SADEMO.DB. Nalezněte jej a překopírujte.
Dále je nutno nadefinovat datový zdroj ODBC. V administrátoru BDE zvolíme
Object
| ODBC Administrator, čímž zobrazíme dialogové okno Administrátora
datových zdrojů ODBC. Na stránce
User DSN stiskneme tlačítko Add
a vybereme ovladač, pro který chceme datový zdroj vytvářet. My vybereme
Sybase
SQL Anywhere 5.0 a stiskneme tlačítko Finish. Je zobrazeno okno
konfigurace ODBC. Pomocí tlačítka
Browse do části Database File
zadáme C:\PRAC\SADEMO.DB, označíme volič Custom a stiskneme
tlačítko Options. Tím zobrazíme další okno, kde v části
Start
Command je nutno zadat úplnou specifikaci souboru DBENG50.EXE
(např. C:\SQLAny50\Win32\DBENG50.EXE). Nalezněte tuto specifikaci a zadejte
ji. V tomto okně již není zapotřebí nic nastavovat a stiskem OK
jej uzavřeme. Okno konfigurace uzavřeme stiskem
OK. Na stránce User
DSN Administrátora datových zdrojů ODBC si povšimněte, že v seznamu
datových zdrojů je již námi vytvořený datový zdroj (Sademo). Okno
Administrátora ODBC také uzavřeme stiskem OK. Až budete používat
tuto databázi, pak je nutno při připojování k ní zadat identifikaci uživatele
a heslo. K databázi se budeme hlásit jako uživatel
DBA a tento uživatel
má heslo SQL. Tyto informace si zapamatujte.
Seznam přezdívek v Administrátoru BDE se zatím nezměnil (seznam se
načítá vždy při spuštění administrátora). Pokud ukončíme práci Administrátora
BDE a spustíme jej znova, pak v seznamu přezdívek již uvidíme přezdívku
Sademo
pro náš nově vytvořený datový zdroj ODBC. Přezdívka tedy byla vytvořena
sama.
To co bylo uvedeno o Administrátoru BDE platí i o samotném C++ Builderu.
Přezdívky jsou načítány pouze při jeho spuštění. Pokud provedeme nějakou
změnu v přezdívkách BDE, pak tato změna se v C++ Builderu projeví až po
jeho dalším spuštění.
V předchozím zadání jsme si vytvořili přezdívku BDE Sademo, kterou
nyní budeme používat při dalším seznamování s databázovými komponentami.
Komponenta Query slouží pro zpřístupňování dat v databázích typu
klient/server. Pokud bychom i pro tento typ databází používali komponentu
Table,
pak některé tabulky se nám nepodaří otevřít (např. ve cvičné databázi Sademo
neotevřeme tabulku Customer - tabulky jsou provázané a databáze
obsahuje také různé příkazy). Nyní se seznámíme s komponentou
Query.
Tato komponenta nemá vlastnost TableName. Nelze tedy přímo zjistit,
ze kterých tabulek se databáze skládá. Pokud se potřebujeme dozvědět, které
tabulky jsou v databázi, pak to lze provést dvěma způsoby. Jednak lze na
formulář umístit dočasnou komponentu Table, nastavit u ní DatabaseName
na správnou přezdívku a v rozbalovacím seznamu vlastnosti TableName
si seznam tabulek můžeme prohlédnout. Druhou možností je, vybrat komponentu
Query
na formuláři a v její místní nabídce zvolit Explore. Tím zobrazíme
Průzkumníka databáze, ve kterém si můžeme zjistit různé věci o databázi
(včetně seznamu tabulek databáze).
Jednou z hlavních vlastností komponenty Query je vlastnost SQL.
Je typu TStringList a obsahuje prováděné příkazy SQL. Hodnotu této
vlastnosti lze nastavit při návrhu v Inspektoru objektů nebo za běhu aplikace
pomocí kódu. Vytvoříme nyní jednoduchou aplikaci, ve které např. zobrazíme
obsah tabulky Customer ze cvičné databáze Sademo. Začneme
vývojem nové aplikace, na formulář umístíme komponentu Query, vlastnost
DatabaseName
nastavíme na Sademo, vlastnost SQL na
SELECT * FROM Customer
a vlastnost Active na true. Na formulář je ještě nutno
vložit komponenty DataSource a DBGrid. Vlastnosti u těchto
komponent nastavíme již známým způsobem (u DataSource vlastnost
DataSet
na Query1 a u DBGrid vlastnost DataSource na DataSource1).
Aplikace je hotova a vidíme, že mřížka zobrazuje obsah tabulky Customer
(pokud bychom použili komponentu Table, pak se nám to nepodaří).
Když budeme vlastnost SQL nastavovat za běhu, pak nesmíme zapomenout
vyprázdnit její předchozí obsah, tzn. je nutno použít např. příkazy:
Query1->SQL->Clear();
Query1->SQL->Add("SELECT
* FROM Customer");
Vlastnost je seznam řetězců a ne samotný řetězec.
Příkazy ve vlastnosti SQL budou provedeny, při volání metody
Open
nebo metody ExecSQL. Pokud vlastnost SQL obsahuje příkaz
SELECT,
pak k jeho použití voláme metodu Open, pokud používáme příkazy INSERT,
UPDATE
nebo DELETE, pak je nutno k provedení příkazu použít metodu ExecSQL.
Nastavení vlastnosti
Active na true má stejný efekt jako
volání metody Open.
V další aplikaci si ukážeme změnu vlastnosti SQL za běhu aplikace.
Začneme vývoj nové aplikace, na formulář umístíme komponentu Query
(změníme u ní DatabaseName na Sademo), komponenty DataSource
a DBGrid (nastavíme u nich vlastnosti obvyklým způsobem) a dvě tlačítka
(s texty Customer a Employee). Obsluha stisku tlačítka
Customer
bude tvořena příkazy:
Query1->SQL->Clear();
Query1->SQL->Add("SELECT
* FROM Customer");
Query1->Open();
a obsluhu stisku druhého tlačítka tvoří:
Query1->SQL->Clear();
Query1->SQL->Add("SELECT
* FROM Employee");
Query1->Open();
Nyní při stisku některého z tlačítek se zobrazí příslušná tabulka.
Příkaz SQL SELECT získává data z databáze. Můžeme používat i jeho složitější
tvary. Např.
Query1->SQL->Clear();
Query1->SQL->Add("SELECT
id, lname, city FROM Customer");
Query1->SQL->Add("WHERE
city = 'Santa Fe'");
Query1->Open();
Příkaz SQL DELETE ruší záznamy z datové množiny (můžeme rušit pouze
záznamy, jejichž zrušení neporuší integritu databáze). Můžeme použít např.
tento kód:
Query1->SQL->Clear();
Query1->SQL->Add("DELETE
FROM Contact WHERE first_name = 'Rose'");
Query1->ExecSQL();
V tomto případě je nutno volat metodu ExecSQL. Totéž platí i
o dalších příkladech. Příkaz SQL INSERT vkládá záznam do datové množiny.
Např.
Query1->SQL->Clear();
Query1->SQL->Add("INSERT
INTO Department");
Query1->SQL->Add("(Dept_id,
Dept_name, Dept_head_id)");
Query1->SQL->Add("VALUES
(600, 'Nic', 501)");
Query1->ExecSQL();
Tento záznam lze vložit pouze jednou, při druhém vložení již nastává
shoda hodnot primárního klíče (je signalizována chyba). Obdobně lze použít
i příkaz UPDATE. Např.
Query1->SQL->Clear();
Query1->SQL->Add("UPDATE
Department");
Query1->SQL->Add("SET
Dept_name = 'xxxxx'");
Query1->SQL->Add("WHERE
Dept_id = 500");
Query1->ExecSQL();
Vidíme, že příkazy SQL můžeme používat jak potřebujeme.
Příkazy SQL mohou také používat parametry. Parametry v příkazech SQL se
podobají proměnným v C++. Parametr v příkazu SQL předchází dvojtečka. Podívejte
se na následující příkaz SQL:
SELECT * FROM Contact
WHERE first_name = :Param1
Parametr se jmenuje Param1. Při provádění tohoto příkazu hodnota
Param1
ve vlastnosti Params je použita místo jména parametru. Např.
Query1->SQL->Add("SELECT
* FROM Contact WHERE first_name = :Param1");
Query1->ParamByName("Param1")->AsString
= "John";
Query1->Open();
Hodnoty parametrů lze nastavovat během návrhu
ve vlastnosti Params pomocí dialogového okna parametrů, ale větší
význam má nastavování parametrů za běhu aplikace. V předchozí ukázce je
použita metoda ParamByName k nastavení hodnoty parametru Param1.
Parametr lze nastavit i příkazem:
Query1->Params->Items[0]->AsString
= "John";
Zde k nastavení hodnoty parametru je použita
vlastnost Items třídy TParams. Výhodnější je ale použití
prvního způsobu, protože si nemusíme pamatovat pořadí parametrů.
Ne všechny prvky příkazů SQL mohou být parametrizovatelné.
Např. většina serverů SQL neumožňuje použít parametr místo jména tabulky.
Komponenta StoredProc reprezentuje uloženou
proceduru na databázovém serveru. Uložené procedury jsou množiny příkazů
SQL, které jsou prováděny jako jeden celek (zaobalují často prováděné databázové
úlohy). Příkazy uložené procedury jsou prováděny na serveru.
Některé uložené procedury používají parametry
a jiné ne. Pro uloženou proceduru bez parametru, nastavíme jméno procedury
a provedeme ji:
StoredProc1->StoredProcName
= "sp_proc";
StoredProc1->Prepare();
StoredProc1->ExecProc();
Pro uloženou proceduru s parametry je nutno nejprve
nastavit parametry a potom proceduru provést:
StoredProc1->StoredProcName
= "sp_proc1";
StoredProc1->ParamByName("cislo")->Value
= 6665;
StoredProc1->Prepare();
StoredProc1->ExecProc();
Jelikož cvičná databáze SQL Anywhere neobsahuje
vhodnou uloženou proceduru, neukážeme si jejich použití.
Komponenta UpdateSQL poskytuje možnost aplikování
změn na datovou množinu určenou pro čtení při povolené odložené aktualizaci.
Normálně datová množina určená pouze pro čtení dovoluje údaje pouze číst.
Když povolíme odloženou aktualizaci, pak je možno takovouto datovou množinu
modifikovat a výsledky těchto modifikací zapsat do databáze. Většina databází
typu klient/server má implicitní akce, které jsou prováděny, když jsou
aplikovány změny v aktualizační vyrovnávací paměti. Komponenta UpdateSQL
umožňuje poskytnout naše vlastní příkazy SQL, pro případ, když má být aktualizován,
vložen nebo zrušen záznam v datové množině určené pouze pro čtení. Např.
komponenta UpdateSQL umožňuje specifikaci implicitních hodnot pro
jisté položky v datové množině.
Vlastnost DeleteSQL umožňuje definovat
dotaz SQL, který bude proveden, když odložené aktualizace jsou aplikovány
a vyrovnávací paměť aktualizací obsahuje rušení záznamů. Obdobně je možno
ve vlastnostech InsertSQL a ModifySQL nadefinovat dotaz SQL
pro vkládání a modifikaci.
Komponenta DataSource poskytuje mechanismus
k propojení komponent datových množin (Table, Query a StoredProc)
s vizuálními komponentami, které zobrazují data (DBGrid, DBEdit,
DBListBox
atd.). Základní funkcí této komponenty je usnadnění provádění změn v naší
aplikaci. Všechny datové komponenty na formuláři jsou propojeny s DataSource,
který je pak propojen s datovými množinami. Protože datové komponenty nejsou
propojeny přímo s datovou množinou, lze snadno změnit datový zdroj a není
nutno se zabývat všemi datovými komponentami. Umožňuje to také snadnou
změnu např. z datové množiny Table na Query.
DataSource má jen několik vlastností.
Vlastnost DataSet je použita k určení připojené datové množiny.
Vlastnost Enabled určuje zda připojené datové komponenty budou zobrazovat
data. Je-li tato vlastnost nastavena na true, pak data jsou zobrazována,
má-li ale hodnotu false, pak datové komponenty jsou prázdné.
Komponenta Session spravuje databázové sezení.
Pokaždé, když spouštíme databázovou aplikaci, pak BDE vytváří globální
objekt Session. Můžeme jej použít pro přístup k současnému databázovému
sezení. Pokud nevytváříme vícevláknové aplikace, pak není nutno vytvářet
svůj vlastní objekt třídy TSession, ale vystačí nám objekt vytvořený
implicitně. TSession má několik zajímavých metod. Metody AddAlias
a AddStandardAlias lze použít k vytvoření přezdívky BDE za běhu
aplikace. Metody GetAliasNames a GetDatabaseNames mohou být
použity k získání seznamu databází. Použijeme je, když chceme nabídnout
uživateli možnost volit databázi ze seznamu. Seznam lze např. vložit do
kombinovaného okna:
Session1->GetDatabaseNames(ComboBox1->Items);
Obdobně lze použít i metody GetTableNames
a GetStoredProcNames.
Komponenta Database umožňuje provádět některé
databázové operace. Potřebujeme ji pouze, když chceme tyto speciální operace
provádět. Následuje popis těchto situací.
Vlastnost KeepConnections je použita k
řízení zpracování databázového připojení při uzavření datové množiny. Pokud
tato vlastnost má hodnotu false, pak při uzavření poslední datové
množiny, je připojení k databázi zrušeno. To vyžaduje opětovné připojení
k databázi při dalším otevření datové množiny. Nastavíme-li tuto vlastnost
na true, pak připojení k databázi je stále udržováno.
Další význam použití komponenty Database
je řízení operace přihlašování. Pokud vlastnost LoginPrompt má hodnotu
false,
pak lze nastavovat přihlašovací parametry. Např.
Database1->Params->Values["user
name"] = "DBA";
Database1->Params->Values["password"]
= "SQL";
Tyto příkazy je možno použít i jako obsluhu události
OnLogin.
Další důvod k použití komponenty Database
je řízení transakcí. Normálně jsou transakce řízeny BDE. Někdy ale transakce
potřebujeme řídit sami. Transakce je zahájena voláním metody StartTransaction.
Provedené změny jsou do databáze zapsány až při volání metody Commit.
Zatím nezapsané změny je možno zrušit metodou Rollback. Úroveň izolace
transakcí je řízena hodnotou vlastnosti TransIsolation.
Komponenta BatchMove je používána ke kopírování
záznamů z jedné datové množiny do jiné. Vlastnost Source specifikuje
zdrojovou datovou množinu a vlastnost Destination cílovou datovou
množinu. Vlastnost Mapping je vyžadována, pokud datové množiny nemají
identické sloupce. Tato vlastnost je seznam řetězců tvaru:
FirstName = FName
LastName = LName
Notes = Comments
Jména sloupců na levé straně jsou cílové sloupce
a sloupce napravo jsou zdrojové sloupce. Kopírování je spouštěno metodou
Execute.
Vlastnost Mode určuje režim kopírování.
Třída TField reprezentuje položky (sloupce)
v databázi. Tato třída nám umožní nastavit atributy položek. Tyto atributy
zahrnují datový typ (string, integer, float, atd.), velikost položky, index
apod. Hodnotu položky můžeme také číst nebo nastavovat prostřednictvím
vlastností typu AsString, AsVariant a AsInteger.
TField je předek více specializovaných
tříd položek. Potomci TField zahrnují TStringField, TIntegerField,
TSmallIntField,
TWordField,
TFloatField,
TCurrencyField,
TBCDField,
TBooleanField,
TDataTimeField,
TTimeField,
TBlobField,
TBytesField,
TVarBytesField,
TMemoField
a TGraphicField. Tyto odvozené třídy rozšiřují funkčnost základní
třídy jen nepatrně. Např. třídy číselných položek mají vlastnost DisplayFormat,
která určuje způsob zobrazení čísla a vlastnost
EditFormat, určující
způsob zobrazení čísla při editaci. Každý potomek
TField odpovídá
specifickému typu databázové položky. Třída TIntegerField je použita,
když typ položky je Integer, atd.
K vlastnostem TField můžeme přistupovat
během návrhu pomocí Editoru položek. Vlastnosti vybrané položky v Editoru
položek jsou zobrazeny v Inspektoru objektů.
Dříve než můžeme položku číst nebo nastavovat
musíme nějakým způsobem položku lokalizovat. To lze udělat třemi způsoby.
Zpřístupňování položky pomocí jejího ukazatele je nejsnadněji použitelná
metoda. Lze ji ale použít pouze tehdy, když máme přidané položky pomocí
Editoru položek. Při přidávání položek pomocí Editoru položek, C++ Builder
vytváří ukazatel na každou položku spojením jména tabulky a jména položky.
Pro tabulku Table1 a řetězcovou položku FirstName,
C++ Builder vytvoří ukazatel typu TStringField nazvaný Table1FirstName.
Tento ukazatel lze použít pro přístup k položce:
Table1FirstName->Value
= "John";
Vlastnost Fields nabízí další možnost
přístupu k položce - podle pozice. Pokud víme, že položka LastName
je první položkou v tabulce, pak k ní lze přistupovat takto:
Edit1->Text = Table1->Fields[0]->Value;
Třetí způsob zpřístupnění položky používá metodu
FieldByName.
Zde potřebujeme znát pouze jméno položky:
Table1->FieldByName("LastName")->AsString
= Edit1->Text;
FieldByName vrací ukazatel TField.
Když již máme ukazatel na jistou položku, pak
lze změnit její hodnotu pomocí vlastnosti Value nebo některou z
vlastností As (AsString, AsInteger, AsBoolean,
atd.). Tyto vlastnosti provádějí převod z jednoho datového typu na jiný.
Nastavení hodnoty položky je jednoduché, např.
Table1->Edit();
Table1->FieldByName("LastName")->AsString
= Edit1->Text;
Table1->Post();
Metoda Edit uvede tabulku do editačního
režimu, tabulku je možno editovat a metodou Post zapíšeme změny
do databáze.
TField má události OnChange a OnValidate.
Událost OnChange je generována vždy při změně hodnoty položky (po
zápisu změny do databáze). Tuto událost lze použít k oznámení změny položky.
Událost OnValidate vzniká před odesláním dat do databáze. V její
obsluze je možno kontrolovat přípustnost dat. Např.
void __fastcall TForm1::Table1ACCT_NBRValidate(TField
*Sender)
{
if (Sender->AsInteger
< 3000)
throw (EDBEditError("Chybné číslo."));
}
Když generujeme výjimku, pak zápis dat do databáze
je zrušen.
Tím je naše seznamování s databázovými aplikacemi
zatím dokončeno. Podrobný popis všech databázových komponent bude uveden
později ve 4. části příručky.
Nyní se budeme zabývat vývojem aplikací,
které chceme uvést na mezinárodní trh. U těchto aplikací je zapotřebí se
zaměřit na internacionalizaci a lokalizaci. Internacionalizace je proces
umožňující naší aplikaci pracovat ve více zemích (respektování kulturních
konvencí cílového státu a také jazyka). Lokalizace je proces transformace
aplikace na funkce ve specifickém státě. Např. aplikaci je nutno modifikovat
k respektování jistých zákonů v různých státech.
Vytvořit internacionalizovanou aplikaci
není obtížné. Musíme umožnit našemu kódu zpracovávat řetězce z mezinárodní
znakové množiny, musíme navrhnout naše uživatelské rozhraní, aby umožňovalo
změnit lokalizaci a je také nutno izolovat všechny zdroje, které musí být
lokalizovány.
Musíme se ujistit, že kód naší
aplikace může zpracovávat řetězce v různých jazycích. Verze US Windows
95 a Windows NT používá znakovou množinu ANSI Latin-1 (1252). Jiné verze
Windows používají jiné znakové množiny. Např. Japonská verze Windows používá
znakovou množinu Shift-Jis (kódová stránka 932), ve které japonské znaky
jsou reprezentovány jedno nebo dvou slabikovými kódy.
Někdy je zapotřebí provést převod
mezi znakovou množinou Windows (ANSI) a znakovou množinou specifikovanou
kódovou stránkou uživatelova počítače (nazvanou znaková množina OEM). Např.
BDE očekává znakovou množinu OEM ve voláních funkcí API. Pokud použijeme
databázové komponenty VCL, pak není nutno se zabývat převodem mezi znakovými
množinami OEM a ANSI. Tyto komponenty provedou všechny nutné převody automaticky.
Při přímém volání API BDE ale musíme provést převod mezi znakovou množinou
ANSI používanou VCL a znakovou množinou OEM používanou BDE.
Některé jazyky mají více znaků,
než je možno uložit do jedné slabiky. Tyto jazyky mají znaky reprezentované
jednoslabikovým kódem a jiné znaky reprezentované dvouslabikovým kódem.
Když zapisujeme kód pro tyto jazyky, pak musíme zajistit, zpracování všech
řetězců pomocí funkcí, které počítají s jedno i dvouslabikovými znaky.
V nápovědě C++ Builderu pod heslem International APInalezneme
seznam všech funkcí RTL, které umožňují pracovat s víceslabikovými znaky.
Nesmíme zapomenout ani na to, že délka řetězce ve slabikách neodpovídá
délce řetězce ve znacích. Je také nutno být opatrný při předávání znaku
jako parametru funkci, neboť velikost znaku obecně není známa. V tomto
případě je vhodné znaky předávat jako ukazatel na znak nebo jako řetězec.
Jinou možností práce s těmito znakovými
množinami je převedení všech znaků na široké znaky (např. Unicode). Široké
znaky jsou vždy dvouslabikové. Použití dekódovacího schématu širokých znaků
má řadu výhod. Je zde přímý vztah mezi počtem slabik řetězce a počtem znaků
řetězce. Nemusíme mít také obavu, že znak budeme hledat od poloviny jiného
znaku. Velkou nevýhodou práce s širokými znaky je to, že Windows 95 nepodporuje
široké znaky ve voláních funkcí API.
K aplikacím můžeme přidávat speciální
služby. Např. pro mnohoznakové jazyky, můžeme požadovat řízení IME (Input
Method Editor), které je použito pro převod stisku kláves uživatelem na
znakový řetězec. Komponenty VCL často nabízejí podporu pro programování
IME. Většina Windowsovských ovladačů, které přímo pracují se vstupem textu
mají vlastnost
ImeName umožňující specifikaci potřebného IME. Globální
proměnná
Screen poskytuje informace o IME dostupných na našem systému.
Nyní se budeme zabývat návrhem uživatelského
rozhraní internacionalizovaných aplikací. Všechen text zobrazovaný uživatelským
rozhraním musí být přeložen. Texty v jednom jazyku mohou být kratší než
jejich překlad. Musíme tedy počítat s tím, že délka textů se může zvětšit.
Dialogová okna, stavové řádky apod. musí mít dostatek místa pro zobrazení
delších textů. Pokud aplikace používá obrázky, pak je vhodné používat takové,
které nevyžadují překlad (nepoužíváme na obrázcích text). Je vhodné také
nepoužívat obrázky, které jsou specifické pro jistou kulturu.
Formáty datumu, času, finančních
částek jsou také závislé na cílové zemi. Pokud používáme pouze formáty
Windows, pak se jejich převodem nemusíme zabývat. Pořadí řazení řetězců
se také v různých zemích liší. Mnoho evropských jazyků používá diakritická
znaménka, která se v různých zemích řadí různě. V některých zemích existují
dvouznakové kombinace, které jsou chápány jako jeden znak. Někdy jeden
znak je řazen jako dva znaky.
Nejobvyklejší úloha lokalizace aplikace
je překlad řetězců, které se zobrazují v uživatelském rozhraní. Je vhodné
všechny řetězce uživatelského rozhraní uložit do samostatného modulu. C++
Builder automaticky vytváří DFM soubor obsahující zdroje pro naši nabídku,
dialogová okna a bitové mapy. Mimo těchto prvků uživatelského rozhraní,
je také vhodné izolovat všechny řetězce (např. chybové zprávy). Zdroje
řetězců nejsou vkládány do souboru DFM, ale můžeme je uložit do RD souboru.
Izolované zdroje zjednodušují proces
překladu do jiného jazyka. Zdroje mohou být přeloženy a vytvořena DLL zdrojů.
DLL zdrojů umožňuje vytvořit program, který podporuje mnoho jazyků, a to
pouhou výměnou DLL zdrojů. Toto jsme viděli v aplikaci textového editoru
v kapitole
Textový editor II.
Průvodce Resource DLL použijeme
k vytvoření DLL zdrojů pro náš program. Při použití tohoto průvodce musíme
mít otevřený uložený projekt. Můžeme vytvořit DLL zdrojů pro každý požadovaný
jazyk. Přípony těchto DLL určují cílové místo (první dva znaky určují jazyk
a třetí znak zemi). Následující kód může být použit k získání kódu místa
pro cílový překlad:
/*
Plnění ListBoxu řetězci a jejich přiřazenými jazyky se zeměmi */
BOOL
__stdcall EnumLocalesProc(char* lpLocaleString)
{
AnsiString LocaleName, LanguageName, CountryName;
LCID lcid;
lcid = StrToInt("$" + AnsiString(lpLocaleString));
LocaleName = GetLocaleStr(lcid, LOCALE_SABBREVLANGNAME, "");
LanguageName = GetLocaleStr(lcid, LOCALE_SNATIVELANGNAME, "");
CountryName = GetLocaleStr(lcid, LOCALE_SNATIVECTRYNAME, "");
if (lstrlen(LocaleName.c_str()) > 0)
Form1->ListBox1->Items->Add(LocaleName + ":" + LanguageName + "-" + CountryName);
return TRUE;
}
/*
Toto volání způsobí provedení zpětného volání pro každé místo */
EnumSystemLocales((LOCALE_ENUMPROC)EnumLocalesProc,
LCID_SUPPORTED);
EXE soubory, DLL a balíčky, které tvoří naší aplikaci obsahují
všechny potřebné zdroje. K nahrazení těchto zdrojů jejich lokalizovanou
verzí, stačí pouze nabídnout lokalizovanou DLL zdrojů, která má stejné
jméno jako soubory EXE, DLL nebo BPL. Při spuštění aplikace je testováno
místo lokálního systému. Pokud je nalezena DLL zdrojů se stejným jménem,
pak je testována její přípona. Pokud přípona vyhovuje jazyku a zemi lokálního
systému, pak naše aplikace používá zdroje z této DLL a to místo zdrojů
ze souborů EXE, DLL nebo BPL. Není-li nalezena vyhovující DLL zdrojů, pak
jsou použity původní zdroje.
Když naši aplikaci chceme použít s jinou DLL zdrojů,
než je určeno lokálním systémem, musíme nastavit položku v registrech Windows.
Pod klíč
HKEY_CURRENT_USER\Software\Borland\Locales přidáme úplnou
specifikaci naší aplikace jako řetězcovou hodnotu a nastavíme datovou hodnotu
na příponu požadované DLL zdrojů. Tím je možno dosáhnout změny jazyka aplikace
bez nutnosti měnit místo našeho systému.
Např. následující funkce může být použita v instalačním
programu k nastavení hodnoty klíče registru, která určuje místo použité
při spuštění aplikace.
void
SetLocalOverrides(char* FileName, char* LocaleOverride)
{
HKEY Key;
const char* LocaleOverrideKey = "Software\\Borland\\Locales";
if (RegOpenKeyEx(HKEY_CURRENT_USER, LocaleOverrideKey, 0,
KEY_ALL_ACCESS, &Key) == ERROR_SUCCESS) {
if (lstrlen(LocaleOverride) == 3)
RegSetValueEx(Key, FileName, 0, REG_SZ, (const BYTE*)LocaleOverride, 4);
RegCloseKey(Key);
}
}
V naší aplikaci použijeme globální funkci FindResourceHInstance
k získání madla současného modulu zdrojů. Např.
LoadString(FindResourceHInstance(HInstance),
IDS_AmountDueName,
szQuery, sizeof(szQuery));
Když již máme aplikaci internacializovanou, pak můžeme vytvořit
lokalizované verze pro různé země, do kterých ji chceme distribuovat. Naše
prvky rozhraní jsou izolovány v souborech DFM a RC. DFM soubor si zobrazíme
jako text (volbou View As Text v místní nabídce návrhového formuláře)
a provedeme požadovaný překlad. Soubory RC jsou textové soubory a můžeme
je tedy snadno převést do cílového jazyka. Je také nutno provést další
úpravy, týkající se různých specifik cílové země.