Umíme to s Delphi: 107. díl – druhy zdrojů (resources)

Dnešní díl seriálu je určen pro všechny, kteří se chtějí dozvědět vše o jednotlivých druzích zdrojů systému Windows (resources), které existují. Prozradíme si nejen jak jednotlivé zdroje vypadají, ale ukážeme si také jejich konkrétní ukázky a vysvětlíme si, které druhy zdrojů můžeme snadno používat v Delphi a u kterých je to složitější.
V minulém dílu seriálu jsme se začali zabývat problematikou zdrojů systému Windows (tzv. resources). Řekli jsme si všechny důležitý úvodní, teoretické informace o zdrojích a jejich formě při programování v Delphi.

Na úvod jsme si vysvětlili, že obecně se zdroje vyskytují v binární podobě uvnitř souborů s příponami *.res. Pokračovali jsme poznámkou, že v Delphi lze o zdrojích hovořit ještě v jedné souvislosti: popis každého formuláře (třeba i s případnými ikonami apod.) je uložen v souboru s příponou *.dfm, který tedy také můžeme chápat jako určitý specifický typ zdrojů. Soubory *.dfm jsou od Delphi verze 5 ukládány v textové podobě, ale i tak mohou nést binární informaci o ikoně.

Následně jsme si vysvětlili, jakým způsobem je realizován vztah program – zdroje. Řekli jsme si, že soubor se zdrojovým kódem a soubor se zdroji jsou na sobě relativně nezávislé, a že chceme-li připojit zdroje k programu, provedeme to v Delphi pomocí direktivy překladače $R. Výsledkem je přilinkování zdrojů k programovému souboru: vznikne tak jeden výsledný oubor *.exe, který obsahuje jak program a data, tak i zdroje. Potřebujeme-li změnit zdroje (a nahradit tak třeba ikonu programu nějakou jinou), můžeme v zásadě bez problémů použít nový soubor se zdroji <.res), ale nezbytnou podmínkou je opětovná kompilace programu. Na tomto místě tedy musíme trochu poopravit tvrzení o relativní nezávislosti zdrojů a programu – nezávislé ano, ale při požadavku na nové zdroje je nutná rekompilace.

Tolik ke stručnému připomenutí a zopakování obsahu minulé části seriálu. Nyní navážeme tam, kde jsme před týdnem skončili: do uvedeného článku se totiž již nevešel přehled jednotlivých zdrojů. Jinak řečeno, musíme si prozradit, co vše vlastně můžeme ve zdrojích uchovávat a co vše se ve zdrojích může skrývat.

Co všechno se může skrývat ve zdrojích?

Už víme, k čemu zdroje obecně slouží a jak se s nimi obecně pracuje, ale stále ještě nevíme, co vše zdrojem může být. Na tomto místě bych rád zdůraznil, že zdroje nejsou výmyslem nebo snad vymožeností Delphi: hovoříme vždy výhradně o zdrojích systému Windows, zdroje jsou systémovým mechanismem a soubory *.res jsou k dispozici při prakticky jakékoliv kategorii okenních aplikací.

Takže – co jsou zdroje? Uvedli jsme si celou řadu vágních a praktických informací, ale rád bych zveřejnil i oficiální, přesnou definici. Dejme tedy slovo firmě Microsoft:

Zdrojem se označují binární data, která lze přidat do spuštěného souboru ve Win32 aplikaci. Zdroj může být buď standardní nebo definovaný. Data ve standardním zdroji popisují ikonu, kurzor, nabídku, dialogový box, bitmapu, rozšířený metasoubor, font, tabulku akcelerátorů (tj. klávesové zkratky – pozn. autora), tabulku zpráv, tabulku řetězců nebo verzi. Zdroje definované aplikacemi, označované také jako uživatelské zdroje, obsahují jakákoliv data vyžadovaná konkrétní aplikací. – Microsoft Developer Network 1999, Platform SDK Nyní se podrobněji podíváme na jednotlivé zmíněné kategorie jednotlivých zdrojů – viz následující podkapitoly.

Tabulka akcelerátorů

Akcelerátor (nebo též klávesová zkratka) je stisk klávesy nebo kombinace stisků klávesy. Mají podobný účel jako třeba nabídky (menu) – umožňují uživateli přístup k sadě příkazů dané aplikace. V Delphi tento typ zdrojů obvykle nevyužíváme, nicméně pokud bystě se rádi dozvěděli podrobnosti, dodám, že tabulka akcelerátorů je ve Windows API implementována jako pole struktur ACCEL, přičemž každá z těchto struktur popisuje právě jeden akcelerátor.

Vytváření tohoto druhu zdrojů se provádí obvykle pomocí příslušného editoru zdrojů. V tomto editoru vytvoříme požadované klávesové zkratky a výsledek zkompilujeme do zmíněné binární podoby <.res). V programovém kódu aplikace pak použijeme funkci Windows API LoadAccelerators.

Do podrobnějšího popisu akcelerátorů se nebudeme pouštět – už proto, že nástroj, který máme při práci v Delphi k dispozici pro úpravu zdrojů – Image Editor, bohužel práci s akcelerátory nepodporuje. Pokud vás však zajímá, jak může vypadat definice akcelerátorů (a jejich následná reprezentace), posloužím vám výpisem zdrojového souboru z Microsoft Visual C++ a následně i snímkem výsledné obrazovky. Znovu připomínám, že následující výpis je uveden pouze pro názornost a pro získání přehledu. Tento výpis však není reprezentací zdroje! Je to jen jakýsi „zdrojový kód zdroje“, z něhož pak následně kompilátor zdroje dokáže vytvořit (zkompilovat) výsledný soubor *.res, který pak bude na úplný závěr přilinkován ke spustitelnému souboru *.exe.

IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE
BEGIN
"N",            ID_FILE_NEW,            VIRTKEY,CONTROL
"O",            ID_FILE_OPEN,          VIRTKEY,CONTROL
"S",            ID_FILE_SAVE,          VIRTKEY,CONTROL
"Z",            ID_EDIT_UNDO,          VIRTKEY,CONTROL
"X",            ID_EDIT_CUT,            VIRTKEY,CONTROL
"C",            ID_EDIT_COPY,          VIRTKEY,CONTROL
"V",            ID_EDIT_PASTE,          VIRTKEY,CONTROL
VK_BACK,        ID_EDIT_UNDO,          VIRTKEY,ALT
VK_DELETE,      ID_EDIT_CUT,            VIRTKEY,SHIFT
VK_INSERT,      ID_EDIT_COPY,          VIRTKEY,CONTROL
VK_INSERT,      ID_EDIT_PASTE,          VIRTKEY,SHIFT
VK_F6,          ID_NEXT_PANE,          VIRTKEY
VK_F6,          ID_PREV_PANE,          VIRTKEY,SHIFT
END

Bitmapy

Bitmapa, další druh zdroje, je grafický objekt používaný k vytváření, manipulaci a uchovávání obrázků ve formě souborů na disku počítače.

Bitmapám bychom mohli klidně věnovat svůj vlastní článek (a možná to časem i uděláme). Na tomto místě však jejich popis přerušíme, neboť práci s bitmapami (a jejich využívání jako zdrojů v Delphi) se budeme věnovat později prakticky.

Kurzory

Kurzor, jak asi nikoho nepřekvapí, je malý obrázek, jehož pozice na obrazovce je ovládána nějakým ukazovacím zařízením, obvykle myší (ale také třeba perem nebo trackballem). Jedná se v podstatě o běžné bitmapy o velikosti 32x32 bodů. Používají se u nich obvykle pouze dvě barvy, ale obecně mohou být kurzory monochromatické nebo barevné a buď statické nebo i animované. Nutno poznamenat, že starší systémy (VGA) nepodporovaly barevné nebo animované kurzory, nicméně s takovými stařečky se dnes již příliš často nesetkáme. A nové systémy, jejichž grafické ovladače používají bitmapy nezávislé na zařízení (device-independent bitmap, DIB), je samozřejmě podporují.

S kurzory jakožto zdroji je možné vcelku bez problémů pracovat i v Delphi.

Dialogové boxy

Ve zdrojích aplikace se obecně mohou vyskytovat také dialogové boxy. Nutno poznamenat,. že tento druh zdrojů se v Delphi také nevyužívá (s dialogy se pracuje přímo v rámci vývojového prostředí, jak to běžně děláme).

Pro úplnost však vysvětleme, že dialogovým boxem se v terminologii Windows má na mysli dočasně zobrazené okno, které zobrazí aplikace za účelem získání uživatelského vstupu.

Protože ani s dialogovými boxy již v dalším textu pracovat nebudeme, posloužím opět alespoň textovým zdrojovým kódem převzatým z projektu v Microsoft Visual C++. Znovu připomínám, že s takovým výpisem se při práci v Delphi pravděpodobně nikdy nesetkáte.

DD_ABOUTBOX DIALOG DISCARDABLE  0, 0, 235, 55
CAPTION "About mdied"
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
FONT 8, "MS Sans Serif"
BEGIN
ICON            IDR_MAINFRAME,IDC_STATIC,11,17,20,20
LTEXT          "mdied Version 1.0",IDC_STATIC,40,10,119,8,
                    SS_NOPREFIX
LTEXT          "Copyright (C) 2002",IDC_STATIC,40,25,119,8
DEFPUSHBUTTON  "OK",IDOK,178,7,50,14,WS_GROUP
END

Tento zdrojový kód se po kompilaci do souboru *.res promění v cosi, co bude pak prostředím a aplikací interpretováno jako následující dialog:

Rozšířené metasoubory

Rozšířené metasoubory, enhanced metafiles, jsou vlastně kolekcemi struktur, které uchovávají obrázek ve formátu nezávislém na zařízení. Jinak řečeno, na rozdíl od běžných bitmap znamená uložení obrázku v metasouboru nezávislost na konkrétním zařízení. Na druhou stranu platí, že jejich vykreslování je obvykle trochu pomalejší než zobrazení běžných bitmap. Proto bychom se vždy měli rozhodnout, zda v naší aplikaci vyžadujeme spíše nezávislost na zařízení nebo rychlost a dostatečný výpočetní výkon. Pokud nám jde spíše o efektivitu, je lepší použít bitmapu než metasoubor. V současnosti existují dva druhy metasouborů – rozšířené metasoubory (enhanced metafiles) a běžné metasoubory ve formátu Windows (Windows-format metafiles). Druhý zmíněný typ je podporován v podstatě již jen kvůli zpětné kompatibilitě a měl by být využíván jen velmi zřídka.

Ani s metasoubory nemůžeme pracovat v rámci editoru zdrojů dodávaného s Delphi – Image Editoru.

Písma (fonty)

Obecně lze říci, že ani písmo (jakožto zdroj) se příliš často nevyužívá, nicméně jeho použití již není úplnou raritou. Pakliže ve své aplikaci používáme nějaké nestandardní, nepříliš běžné a málo rozšířené písmo, je možné jej dodávat společně s aplikací právě ve formě zdrojů. Není to však příliš časté, protože obvykle je lepším řešením příslušné písmo prostě nainstalovat do systému.

Ikony

O ikonách asi nemá smysl dlouze hovořit. Jedná se o malé bitmapy o velikosti buď 32x32 bodů nebo 16x16 bodů. Malé ikony si můžete prohlédnout třeba v Průzkumníku Windows (Zobrazit – Malé ikony), velké ikony vidíte třeba na ploše nebo také v Průzkumníku (Zobrazit – Velké ikony). Ikony jsou nakresleny často v 16 barvách, maximální počet je pak 256 barev.

Nabídky (menu)

Tvar a vzhled jednotlivých nabídek v aplikaci bývá uchováván také v souborech zdrojů. Z toho pak plyne třeba možnost poskytovat různé jazykové mutace aplikací – a jednoduše mít více jazykových verzí jednotlivých nabídek.

Tabulky řetězců

Dovolím si tvrdit, že tabulky řetězců bychom mohli prohlásit za jednu z nejpoužitelnějších součástí zdrojů. K čemu slouží? Ve většině aplikací pracujeme s celou řadou řetězců – vypisujeme nejrůznější hlášení, vypisujeme výzvy a výsledky apod. Pokud bychom místo samotného řetězce použili v programu jen jakýsi dohodnutý identifikátor řetězce a samotný řetězec pak „vytáhli“ odkudsi z vnějšku, například ze zdroje, mohli bychom velice jednoduše nahradit jednu sadu řetězců nějakou jinou – opět se nabízí asi nejlepší využití při přípravě nějaké nové jazykové mutace naší aplikace.

Jenže na tomto místě je hned nutné upozornit na poměrně závažný problém: Delphi nedisponují žádnou zvláštní podporou těchto typů zdrojů. V Image Editoru s řetězci pracovat nemůžeme, a tak pokud chceme při programování v Delphi využívat tuto skvělou možnost uchovávat více skupin řetězců, nezbývá nám, než se pohlédnout po nějakém jiném nástroji (viz minulá část seriálu). Nezbývá než povzdechnout, že to je velká škoda.

A tak si opět ukážeme alespoň to, jak jsou tabulky řetězců uloženy před kompilací do zdrojů v Microsoft Visual C++:

STRINGTABLE PRELOAD DISCARDABLE
BEGIN
IDR_MAINFRAME          "mdied"
IDR_MDIEDTYPE        "\nMdied\nMdied\n\n\nMdied.Document\nMdied Document"
END
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
AFX_IDS_APP_TITLE      "mdied"
AFX_IDS_IDLEMESSAGE    "Ready"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_INDICATOR_EXT        "EXT"
ID_INDICATOR_CAPS      "CAP"
ID_INDICATOR_NUM        "NUM"
ID_INDICATOR_SCRL      "SCRL"
ID_INDICATOR_OVR        "OVR"
ID_INDICATOR_REC        "REC"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_FILE_NEW            "Create a new document\nNew"
ID_FILE_OPEN            "Open an existing document\nOpen"
ID_FILE_CLOSE          "Close the active document\nClose"
ID_FILE_SAVE            "Save the active document\nSave"
ID_FILE_SAVE_AS        "Save the active document with a new name\nSave As"
ID_APP_ABOUT            "Display program information, version number and copyright\nAbout"
ID_APP_EXIT            "Quit the application; prompts to save documents\nExit"
ID_FILE_MRU_FILE1      "Open this document"
ID_FILE_MRU_FILE2      "Open this document"
ID_FILE_MRU_FILE3      "Open this document"
ID_FILE_MRU_FILE4      "Open this document"
ID_FILE_MRU_FILE5      "Open this document"
ID_FILE_MRU_FILE6      "Open this document"
ID_FILE_MRU_FILE7      "Open this document"
ID_FILE_MRU_FILE8      "Open this document"
ID_FILE_MRU_FILE9      "Open this document"
ID_FILE_MRU_FILE10      "Open this document"
ID_FILE_MRU_FILE11      "Open this document"
ID_FILE_MRU_FILE12      "Open this document"
ID_FILE_MRU_FILE13      "Open this document"
ID_FILE_MRU_FILE14      "Open this document"
ID_FILE_MRU_FILE15      "Open this document"
ID_FILE_MRU_FILE16      "Open this document"
ID_NEXT_PANE            "Switch to the next window pane\nNext Pane"
ID_PREV_PANE            "Switch back to the previous window pane\nPrevious Pane"
ID_WINDOW_NEW          "Open another window for the active document\nNew Window"
ID_WINDOW_ARRANGE      "Arrange icons at the bottom of the window\nArrange Icons"
ID_WINDOW_CASCADE      "Arrange windows so they overlap\nCascade Windows"
ID_WINDOW_TILE_HORZ    "Arrange windows as non-overlapping tiles\nTile Windows"
ID_WINDOW_TILE_VERT    "Arrange windows as non-overlapping tiles\nTile Windows"
ID_WINDOW_SPLIT        "Split the active window into panes\nSplit"
ID_EDIT_CLEAR          "Erase the selection\nErase"
ID_EDIT_CLEAR_ALL      "Erase everything\nErase All"
ID_EDIT_COPY            "Copy the selection and put it on the Clipboard\nCopy"
ID_EDIT_CUT            "Cut the selection and put it on the Clipboard\nCut"
ID_EDIT_FIND            "Find the specified text\nFind"
ID_EDIT_PASTE          "Insert Clipboard contents\nPaste"
ID_EDIT_REPEAT          "Repeat the last action\nRepeat"
ID_EDIT_REPLACE        "Replace specific text with different text\nReplace"
ID_EDIT_SELECT_ALL      "Select the entire document\nSelect All"
ID_EDIT_UNDO            "Undo the last action\nUndo"
ID_EDIT_REDO            "Redo the previously undone action\nRedo"
END

STRINGTABLE DISCARDABLE
BEGIN
AFX_IDS_SCSIZE          "Change the window size"
AFX_IDS_SCMOVE          "Change the window position"
AFX_IDS_SCMINIMIZE      "Reduce the window to an icon"
AFX_IDS_SCMAXIMIZE      "Enlarge the window to full size"
AFX_IDS_SCNEXTWINDOW    "Switch to the next document window"
AFX_IDS_SCPREVWINDOW    "Switch to the previous document window"
AFX_IDS_SCCLOSE        "Close the active window and prompts to save the documents"
AFX_IDS_SCRESTORE      "Restore the window to normal size"
AFX_IDS_SCTASKLIST      "Activate Task List"
AFX_IDS_MDICHILD        "Activate this window"
END

Je evidentní, že pokud nyní chceme přeložit aplikaci do jiného jazyka, stačí napsat nový zdroj (viz výše uvedený programový výpis, kde k jednotlivým identifikátorům napíšeme řetězce v jiném jazyce. Pak stačí v Microsoft Visual C++ provést opětovný překlad projektu a nová jazykové verze aplikace je na světě.

Informace o verzi aplikace

Tento druh zdrojů umožňuje uchovávat informace o verzi aplikace, o jejím autorovi apod. Ani na tomto místě nenalezneme žádnou výraznou podporu Delphi: s verzemi se v Delphi pracuje známým způsobem pomocí integrovaného vývojového prostředí: z nabídky Project zvolíte Options a vyberete záložku Version. Tam je pak možné vyplnit všechny požadované údaje. Podpora zdrojů s informacemi o verzích by se však asi také občas mohla hodit.

Co zo toho všeho plyne?

Z předchozích odstavců byste si měli podle mého soudu odnést prakticky jediný závěr: zdrojů existuje celá řada a umožňují uchovávat široké spektrum údajů – od obrázků až po řetězce. Na druhou stranu podpora zdrojů v Delphi není příliš výrazná. Tedy – u samotného Delphi (jako takového) by nám to příliš nevadilo, protože Delphi je postaveno na jiných principech než na práci se zdroji. U Delphi nám bohatě stačí, když podporuje zdroje tak, jak to dělá – prostě umožňuje přilinkovat soubor se zdroji k aplikaci. Tečka. Ale hlavní problém nastává u dodávaného podpůrného nástroje (Image Editor), který umožňuje pracovat prakticky jen se třemi druhy zdrojů:

  • s ikony,
  • s kurzory,
  • s bitmapami.

Pokud bychom chtěli v Image Editoru pracovat s řetězci, nabídkami nebo jinými nástroji, máme bohužel smůlu, což je trochu škoda.

Ještě dodám jednu věc – pokud někdo z vás pracuje v Microsoft Visual C++ nebo má k dispozici jiné vývojové prostředí z dílky Microsoftu (všeliké variace na Microsoft Visual XXX), možná jste postřehli, že v těchto nástrojích je práce se zdroji jaksi nedílnou, integrální součástí celého vývojového prostředí. Vskutku, například Microsoft Visual C++ je na zdrojích vlastně postaveno; všechny fragmenty aplikace, které lze uchovávat ve zdrojích, jsou v nich uchovávány. Z toho důvodu pokud třeba v prostředí pracujeme s nějakými ovládacími prvky, tlačítky apod., pracujeme ve své podstatě se zdroji a máme k dispozici editor zdrojů, který je vlastně součástí prostředí.

Na závěr

Dnešní článek se podrobně zabýval jednotlivými druhy zdrojů. Ukázali jsme si, jaké všechny zdroje připadají v úvahu a prozradili jsme si, že v Delphi můžeme bez dalších podpůrných nástrojů snadno pracovat s kurzory, ikonami a bitmapami.

Příští díl seriálu bude již konečně zcela praktický: ukážeme si, jak práci se zdroji v Delphi realizovat.

Váš názor Další článek: Další členové rodiny Mimail

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