× Aktuálně z oboru

Programátoři po celém světě dnes slaví Den programátorů [ clanek/2018091300-programatori-po-celem-svete-dnes-slavi-den-programatoru/ ]
Celá zprávička [ clanek/2018091300-programatori-po-celem-svete-dnes-slavi-den-programatoru/ ]

Win32 API - 3. díl - Resource

[ http://programujte.com/profil/20356-kamil-skala/ ]Google [ ?rel=author ]       [ http://programujte.com/profil/118-zdenek-lehocky/ ]Google [ ?rel=author ]       17. 2. 2006       44 779×

Dnes si povíme něco o zdrojích Windows (Resource), koukneme se na vlastní ikonu aplikace i ikonu systémové nabídky a naťukneme menu programu (místní nabídku)..

V minulém díle jsme již konečně zvládli vytvořit okno aplikace. Okno, které již začíná vypadat jako program pro Windows, ale po méně bedlivějším zkoumání si asi každý všiml, že má jisté nedostatky, jak ve vzhledu, tak ve funkci. Pokusíme se s tím něco udělat.

Prvním a hlavním nedostatkem je, že program nemá svou vlastní ikonu ani ikonu systémové nabídky, ta je implicitní, dána konstantou IDI_APPLICATION ve třídě okna.

Jistě jste si všimli, že každý program se identifikuje svou jedinečnou ikonou aplikace a většinou mívá i odlišnou ikonu sys. nabídky. Jak toho ale docílit? Jak říct aplikaci, že má používat právě námi zvolenou ikonu? V prvním bodě musíme příslušnou ikonu vlastnit. Jestli si ji nakreslíte nebo někde stáhnete, to je už na vás.

Budeme předpokládat, že ji máme a jak ji tedy načíst do našeho programu, aby se aplikace touto ikonou identifikovala? Musíme si jí tedy načíst do zdrojů.

Zdroje neboli Resource je soubor s příponou .rc, kterému se říká kompilovaný script zdrojů. Zdroje jsou data a často jsou uložena v *.exe souboru. Výhodou je, že nemusíte s aplikací šířit dalsí grafické nebo jiné soubory, které lze importovat do zdrojů.

A jaké zdroje jsou?

Především se jedná o tyto typy zdrojů:

Ikony, kurzory, znakové řetězce, uživatelské zdroje, nabídky, klávesové zkratky, dialogy a bitmapy.

Každý z nich je jedním typem zdroje. Zdroje nejsou umístěny ve společné části s proveditelnými daty. Takže je nelze adresovat přímo pomocí proměnných v kódu. Windows nabízí pro práci se zdroji funkce, které nahrávají jednotlivé zdroje do paměti, aby je mohl program použít. Už jsme prakticky se dvěmi těmito funkcemi pracovali v minulém díle. Jednalo se o funkce LoadIcon a LoadCursor ve třídě okna. V minulém díle tyto funkce nahrávaly binární ikony nebo kurzory přímo z Windows a vracely handle této ikony nebo kurzoru.

V API budeme implementovat script zdroje pomocí souboru "nazev.rc" a hlavičkového souboru "nazev.h", ale nejčastěji, a to právě ve VC++, nese implicitně tato hlavička název "Resource.h", záleží na kompilátoru co preferuje. Každý zdroj v souboru .rc je identifikován identifikační konstantou, nebo i názvem. Konstanty, které identifikují zdroje, jsou definovány právě v souboru "zdroje.h", kde název bude brán nejčastěji dle názvu projektu. Script zdroje má většinou název shodující se s názvem projektu. Budu-li mít projekt demo, tak script se bude jmenovat "demo.rc" a hlavička zdroje třeba "demo.h". Ale je to také závislé na kompilátoru.

Dev-C++ si vytváří svůj vnitřní script, který includuje náš script, ve kterém provádíme změny a vytváří si také svou hlavičku, my už jinou nevytváříme, jen ji editujeme. U VC++ si vytvoříme vlastní script zdroje, ale hlavička se nám vždy vytvoří implicitní, needitujeme ani script ani hlavičku, to za nás dělá kompilátor a to je hlavní rozdíl v práci se zdroji v těchto různých prostředích.

Hlavičkový soubor "zdroje.h" musí být includován před WinMain(), tak jako "windows.h". A též i v skriptu zdrojů. Tady záleží na kompilátoru, některé si hlavičku do scriptu naincludují sami, jinde si musíme pomoci ručně, to je případ Dev-C++, kde musíme ručně vytvořit soubor *.rc.

Malé upozornění, můžeme používat jen jeden skript zdrojů! To neznamená, že jich nemůžeme mít víc, ale že se kompilovat do aplikace bude jen ten jeden hlavní. Dají se používat metody podobné práci s hlavičkovými soubory. Tzn., že do hlavního skriptu importuju další skripty, které obsahují zdroje. Tento postup používá právě Dev-C++.

A teď již k praxi.

Pokud jste ještě nesmazali projekt z minulého dílu, tak je to jedině dobře, jak sem psal v samém začátku, budem postupovat formou vývoje, vylepšování a přidávání, takže se už zde budu zabývat pouze aspekty, které se týkají toho, co právě probíráme.

Takže, otevřete si projekt z minulého dílu a jdeme na to:

Dev-C++

Začnu tím složitějším přístupem, a to je Dev-C++. Dev nemá žádné nástroje pro načtení zdrojů do scriptu (alepsoň o tom nevím), ale třeba se jich dočkáme.

Nyní když máme projekt otevřený, vložíme do něj script zdroje. Klepneme myší v menu na příkaz Soubor(File) --> Nový(New) --> Definice zdrojů(Resource File).

Tím se nám do projektu přidá nový Resource script. Když se teď kouknete do složky s projektem, vytvoří se tam skript s názvem projektu a podtržítko private: "demo_private.rc" a k němu "demo_private.h" , to je script a hlavička zdrojů, o kterých jsme mluvili. Tento private skript je hlavní skript zdrojů, který se kompiluje k exe a includuje do sebe náš skript, který si teď uložíme nejlépe pod názvem projektu. Tak ho tedy uložme.

V Dev-C++ se může stát, že se nám nepřepíše v demo_private.rc název skriptu při uložení, který se tam includuje a kompilace bude hlásit chybu, pokud ano, ručně přepište název na takový, jaký jste zvolili pro uložení, i když je tam nepsáno, že se nemá editovat :-).

Dejme tomu, že jsme si skript uložili pod názvem, "zdroje.rc". Teď kdybyste chtěli aplikaci přeložit, se zlou se potážete, a to s chybou, že ve scriptu nemáme žádný zdroj! Musíme tedy nějaký vložit - ikonu.

Dám příklad, že ve složce s projektem máme složku "grafika", do které si uložíme veškerou grafiku (ikony, kurzory, bitmapy atd.), se kterou chceme v našem programu pracovat, a tam bude i naše ikona, tak musíme do scriptu zadat cestu k této složce a ikoně, aby měl kompilátor odkud tuto ikonu natáhnout a zkompilovat do scriptu.

Napíšeme tedy:

#include "zdroje_private.h"
#include "afxres.h"
//**************ZDROJE***********************


IDI_ICON ICON DISCARDABLE "grafika/ikona.ico"

Kde první hlavičkový soubor zdroje_private.h, obsahuje definice číselných konstant zdrojů. Hlavičkový soubor afxres.h je standardní soubor pro práci se zdroji. Obsahuje standardní definice konstant pro práci se zdroji, ale můžeme se obejít i bez něj a vytvářet konstanty vlastní. Následuje vlastní definice zdroje ikony.

IDI_ICON ICON DISCARDABLE "grafika/ikona.ico

Kde IDI_ICON je číselná konstanta, která je definována v "zdroje_private.h", ukážeme si za chvíli. ICON je příkaz pro vytváření zdroje ikony. DISCARDABLE říká, že Windows můžou tuto ikonu podle potřeby odstranit z paměti kvůli uvolnění místa. Ikona může být kdykoliv znovu natažena do paměti Windows bez jakékoliv činnosti programu. Atribut DISCARDABLE je výchozí a nemusí být deklarován.

Dále je zapotřebí definovat konstantu zdroje ikony. To se provádí v hlavičkovém souboru "zdroje_private.h", který jsme připojovali na začátku skriptu. Když ho otevřete, již je v něm obsah vložený kompilátorem. Ten tam nechte a někam na konec přidejte tento řádek:

#define IDI_ICON 101

Toto by vám mělo být známé. Definice konstanty IDI_ICON (kterou jsme použili ve skriptu) s číselnou hodnotou 101. Číslo 101 udává ID zdroje. Bývá dobrým zvykem určit si rozsah pro jednotlivé zdroje a tohoto rozsahu se držet, abyste v tom za chvíli neměli bordel. Viz např. tento komentář:

//********IKONY A KURZORY 101 – 201***********
//********STRINGY 202 – 1000************
//********BITMAPY 1001 – 2001***********
//atd...

Rozsah je na vás, zpravidla se ID okolo 4000 vyhrazuje kompilátorem pro jeho potřeby. Teď už zbývá jen includnout hlavičku "zdroje_private.h" k ostatním hlavičkám aplikace nejlépe za "windows.h" . A teď již můžeme použít funkci pro nahrání ikony do aplikace.

Volání funkce:

wc.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON));

Ve třídě okna, nám načte ikonu a vrátí handle na tuto ikonu. První parametr je handle instance, který určuje, z jakého souboru handle pochází. Použití hInstance znamená, že zdroje pochází z programu samotného (takže soubor *.exe). Druhý parametr je vlastně definován jako ukazatel na řetězec znaků. Na zdroje se lze tudíž odkazovat jak pomocí znakového řetězce, tak i číselného identifikátoru.

O tom už napovídá i ono makro MAKEINTRESOURCE (make an integer into a resource string). To vytvoří z čísla ukazatel na řetěze.

#define MAKEINTRESOURCE(i) (LPSTR) ((DWORD) ((WORD) (i)))

Funkce LoadIcon() ví, že když je horní slovo druhého parametru 0, potom je spodní slovo číselný identifikátor ikony. Identifikátor ikony musí být 16bitová hodnota.

Používá-li se předdefinovaný identifikátor, Windows poznají, že jde o předdefinovaný zdroj Windows, protože je parametr instance NULL. Definice IDI_APPLICATION se nachází v winuser.h.

Identifikátor zdroje můžeme změnit na řetězec tak, že ho v *.rc souboru uzavřeme do uvozovek. Takže máme 3 způsoby, jak použít identifikátor zdroje:

IDI_ICON
101
“IDI_ICON“

Výhoda textového názvu ikony může být v tom, že ji můžete dát název aplikace a pak ikonu načíst voláním funkce LoadIcon(instance, szAppName). Což vypadá trochu přehledněji, než použití makra.

Je ještě jeden způsob identifikace ikony. V *.rc souboru se místo identifikátoru IDI_ICON použije číselné ID:

101 ICON DISCARDABLE „grafika/ikona.ico“

Nna ikonu se lze poté odkazovat takto:

hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(101));
a nebo :
hIcon = LoadIcon(hInstance, TEXT(“#101“));

Windows rozpoznají znak # jako indikátor čísla v podobě ASCII.

A to je vše.

U sm_Ikony (malá ikona systémové nabídky) je postup naprosto stejný, jen musíte dát bacha na to, že pro ikonu aplikace se používá ikona o rozměrech 32×32 bodů a pro systémovou nabídku se používá ikona o rozměrech 16×16 bodů. Pozn.: Pokud použijete jen ikonu aplikace, automaticky se vám tato ikona přiřadí i jako ikona sys. nabídky, i když ji ve třídě máte jako NULL.

VC++

Co se týče použití Funkce LoadIcon() ve VC++, není zde rozdílu. Akorát je trošku jiný postup při vytváření zdrojů. Lépe řečeno, téměř nic nemusíte dělat. Ukázka, jak na to ve VC++:

Otevřeme projekt a klepneme na : Project --> Add to project --> New File --> New. A vložíme novy Resource script a pojmenujeme ho třeba podle názvu projektu. Automaticky se nám vytvoří "Resource.h". Tento název je implicitní a nedoporučuju to měnit.

Teď když máme vybrán soubor zdroje (vzhledově jen složka), klepneme na ni pravým myšítkem a zvolíme insert. Z tabulky si zvolíme, jaký zdroj chceme vkládat. Vybereme si tedy Ikonu a klepneme na Import, při zvolení New by se nám otevřel editor zdrojů podobný programu malování, kde bychm si mohli nakreslit vlastní ikonu, tím se zde zabývat nebudu. V browseru si najdeme naší ikonu a odklepneme tlačítko Import. Otevře se náhled ikony, kde si jí můžeme ještě dodatečně upravit, toto okno zavřeme a již vidíme, že nám v seznamu zdrojů přibyla složka Icon a stromově v ní naše ikona. Klepnutím pravým myšítkem na ní a zvolením Properties si můžeme změnit název identifikátoru, poté Enter.

V hlavičkovém souboru "Resource.h" nemusíme nic editovat ani nemusíme do skriptu includovat tuto hlavičku, to už kompilátor udělal za nás, pouze musíme tuto hlavičku includnout do hl. zdrojového souboru, jako u Dev-C++.

Upravíme funkci LoadIcon() a zkompilujeme, mělo by se nám objevit už nám známé okno, ale s novou ikonou a ikona aplikace by také měla být ta naše a ne standard z Windows. Po kompilaci se můžete kouknout do Resource.h, že se vše správně nastavilo (název konstanty, číselné ID atd.).

Kurzory

Práce s kurzorem ve zdrojích je úplně stejná jako s ikonou. Pouze místo klíčového slova "ICON" použijeme "CURSOR", jinak není rozdílu. Kurzor je obyčejně jednobarevný (ale jsou i výjimky) s rozměry 32×32 bodů.

Pro nahrání vlastního kurzoru použijeme funkci LoadCursor(), kterou jsme použili i v minulém díle, parametry jsou shodné s LoadIcon(). Takže:

wc.hCursor = LoadCursor(hInstance,MAKEINTRESOURCE(IDC_CURSOR));

Ostatní drobnosti jsou shodné s ikonou. Myslím, že netřeba bližšího rozboru, opakoval bych, co již bylo řečeno.

Kdykoliv se myš zobrazí nad oknem definovaném na této třídě, zobrazí se námi definovaný kurzor. Pozn.: Kurzor lze změnit i za běhu aplikace použitím funkce SetCursor(hCursor), a to ve zprávě WM_MOUSEMOVE, jinak by byl překreslen kurzorem definovaným ve třídě okna. Ale k tomu se ještě vrátíme časem, až si budeme hrát s myší :-).

Místní nabídka

Jistě jste už ve spoustě programů viděli, že mají tzv. menu. Slíbil jsem, že se na něj koukneme, tak tedy:

Už máme poměrně dost zkušeností se zdroji, ale tvorba menu, hlavně v Dev-C++ je přeci jen trošičku odlišná a tak se u ní taky na chvilku zastavíme.

Každá položka nabídky se dá rozdělit na tři charakteristiky:

  • Co se má objevit. Je to buď řetězec nebo bitmapa.
  • Číslo (ID), které Windows zasílají zprávě WM_COMMAND, nebo handle rozbalovací nabídky, kterou Windows zobrazí, když ji uživatel vybere.
  • Atributy položky nabídky.
  • Když píšeme text položky nabídky, můžeme použít ampersand (&) pro určení písmene rychlé volby, které bude podtržené. Kde po stisku ALT+písmeno vyvolá právě tuto nabídku. Nabídku můžeme nastavit i jako zašedlou (Grayed - nepřístupná), položka nebude generovat žádnou zprávu, nebo zaškrtnutou. Ale také můžeme použít oddělovač (SEPARATOR). U rozbalovacích nabídek můžeme použít v textovém řetězci formátovací značku tabulátoru ( ). Text následující za tímto znakem je umístěn do nového sloupce, který je posunutý v pravo o takový počet mezer, aby se přizpůsobil nejdelšímu textu v prvním sloupci nabídky. Znak (a) zarovná text doprava následující za ním. Hodnoty ID musejí být jedinečné. Podle konvence se budeme držet označení předpony IDM (ID Menu). Třeba IDM_SOUBOR.

    Dev-C++

    Znovu editujeme nám již známý "zdroj.rc" a připíšeme do něj tento kód:

    MAINMENU MENU DISCARDABLE
    BEGIN
         POPUP "&Soubor"              
         BEGIN
              MENUITEM "&Nový",       IDM_NEW
              MENUITEM "&Otevřít",    IDM_OPEN
              MENUITEM SEPARATOR
              POPUP "Ta&jemství"
              BEGIN
                    MENUITEM "&Tajemná truhla",   IDM_SECRET
              END      
         END
         POPUP "&Ostatní"
         BEGIN
              MENUITEM "&Nápověda",    IDM_HELP 
              MENUITEM "&Konec",       IDM_CLOSE
              MENUITEM SEPARATOR
              MENUITEM "&O Aplikaci",  IDM_ABOUT
         END     
    END

    Věřím, že po kratším zkoumání budete schopni si nabídku upravit dle svých představ. Asi není třeba bližšího popisu.

    MAINMANU - název menu
    MENU - klíčové slovo, informující, že jde o menu, jako jsme u ikon používali ICON.
    DISCARDABLE - to už známe
    POPUP - hlavní sekce
    BEGIN - začátek bloku
    MENUITEM - položka nabídky a následuje její popis (co se zobrazí) a ID
    END - konec bloku

    Další POPUP v bloku vytvoří vnořenou nabídku. A teď ještě musíme do hlavičky zdroje (zdroj.h) vložit identifikátory konstant, budeme postupovat jako u ikon.

    Takže vložíme toto:

    #define IDM_NEW    40001
    #define IDM_OPEN   40002
    #define IDM_SECRET 40003
    #define IDM_HELP   40004 
    #define IDM_CLOSE  40005
    #define IDM_ABOUT  40006

    A teď jen načteme menu ve třídě okna:

    wc.lpszMenuName = “MAINMENU“;

    A hurá, můžeme kompilovat :-)

    Mělo by se nám objevit okno aplikace již s ikonou a menu :-).

    VC++

    Tak zde je to jednodušší jako u ikon, zase pravým tlačítkem myši na zdroje a zvolíme Insert, vybereme Menu a klepneme na New. Objeví se nám intuitivní editor nabídek, jaký můžeme znát třeba z Visual Basicu nebo Delphi. Jak zde vytvořit menu nechám každému jako kvíz, je to opravdu tak jednoduché, že na to každý musí přijít. Postup nastavení je podobný nastavení vlastností ikony. Když máme menu navržené, pouze ho načtem opět pomocí funkce LoadMenu a zkompilujeme. Máme vyhráno :-).

    Snad vás tento podrobný návod - krok za krokem - moc nevyčerpal, ale pomohl :-).

    Příště si ukážeme, jak reagovat na příkazy menu a naučíme se vypisovat text do klientské oblasti.


    Článek stažen z webu Programujte.com [ http://programujte.com/clanek/2006021402-win32-api-3-dil-resource/ ].