Trochu více o ikonách a kurzorech v C++

V tomto článku si řekneme trochu více o možnostech použití ikon a kurzorů a o jejich vzájemném nahrazení.

Ve většině případů programátor používá běžné funkce LoadIcon a LoadCursor, které načítají tyto typy zdrojů ve standardní velikosti a barevné hloubce. Slovem „standardní“ je myšleno systémové nastavení, tj. velikost ikony a počet barev použitých pro zobrazování ikon. Většina ikon a kurzorů ve skutečnosti obsahuje více "obrázků" pro různá nastavení zobrazovacího zařízení, funkce LoadIcon nám automaticky vybere ten "vhodný". Podívejme se nejprve jako obvykle na screen-shot ukázkové aplikace a řekněme si, jak na to:

Klepněte pro větší obrázek

V horní části dialogu jsou 4 prvky typu "STATIC", jimiž lze nastavit ikonu (ve formě handle HICON), kterou mají zobrazovat. Pokud chceme specifikovat více možností načtení ikony, použijeme funkci

HANDLE LoadImage(
  HINSTANCE hinst, // handle modulu
  LPCTSTR lpszName, // jméno nebo identifkátor obrázku
  UINT uType, // typ obrázku
  int cxDesired, // požadovaná délka
  int cyDesired, // požadovaná výška
  UINT fuLoad // volby načtení
);

Tato funkce je univerzálním rozšířením funkcí LoadIcon, LoadCursor a LoadBitmap. Dává nám více možností, například načítání grafiky ze souboru. Stručně k jednotlivým parametrům:

  • hinst - handle modulu obsahujícího zdroje. V případě, že načítáme ze souboru, hodnota musí být NULL.
  • lpszName - jméno nebo identifikátor ve zdrojích (resources) nebo jméno grafického souboru.
  • uType - typ grafiky
    • IMAGE_BITMAP - načítáme bitmapu
    • IMAGE_CURSOR – načítáme kurzor
    • IMAGE_ICON – načítáme ikonu
  • cxDesired - požadovaná délka načteného obrázku
  • cyDesired - požadovaná výška obrázku
  • fuLoad - volby načtení. Úplný popis naleznete v dokumentaci, zde jen o některých
    • LR_DEFAULTSIZE - použije výchozí rozměry ze systémové metriky a ignoruje hodnoty cxDesired a cyDesired
    • LR_LOADFROMFILE - načítáme ze souboru s názvem, který je dán parametrem lpszName
    • LR_LOADTRANSPARENT - všechny pixely s barvou stejnou jako první pixel (souřadnice 0,0) jsou nahrazeny systémovou barvou oken (COLOR_WINDOW)
    • LR_MONOCHROME - načítáme černobíle
    • LR_SHARED - handle je sdílené, pokud načítáme opakovaně stejný obrázek. Pokud tuto volbu neuvedeme, měli bychom "po použití" uvolnit paměť příslušnou funkcí (pro bitmapu DeleteObject, pro ikonu DestroyIcon, pro kurzor DestroyCursor). K tomu ještě poznámku, že toto sdílení je u funkcí LoadIcon a LoadCursor „nastaveno natvrdo“, proto při jejich použití žádné funkce type Deletexxxxx nevoláme.

    Nyní se podívejme na praktickou demonstraci této funkce. V horní části dialogu jsou čtyři prvky "STATIC" (v editoru zdrojů jako "Picture", kde jako "Type" zvolíme Icon), kterým jsou ve funkci InitDialog přiřazeny handle ikon získané uvedenou funkcí:

    // … kód funkce InitDialog
    GetDlgItem(IDC_ICON16)->SendMessage(STM_SETICON,
        (WPARAM)(HICON)LoadImage(AfxGetInstanceHandle(),
          MAKEINTRESOURCE(IDI_ICON1),
          IMAGE_ICON, 16, 16, LR_SHARED));
    GetDlgItem(IDC_ICON32)->SendMessage(STM_SETICON,
        (WPARAM)(HICON)LoadImage(AfxGetInstanceHandle(),
          MAKEINTRESOURCE(IDI_ICON1),
          IMAGE_ICON, 32, 32, LR_SHARED));
    GetDlgItem(IDC_ICON48)->SendMessage(STM_SETICON,
        (WPARAM)(HICON)LoadImage(AfxGetInstanceHandle(),
          MAKEINTRESOURCE(IDI_ICON1),
          IMAGE_ICON, 48, 48, LR_SHARED));
    GetDlgItem(IDC_ICON_CUSTOM)->SendMessage(STM_SETICON,
        (WPARAM)(HICON)LoadImage(AfxGetInstanceHandle(),
          MAKEINTRESOURCE(IDI_ICON2),
          IMAGE_ICON, 128, 96, LR_SHARED));
    // ….

    Jak vidíte, lze ikonu roztáhnout do libovolného rozměru, který pak bude mít při svém zobrazení.

    Nyní si řekněme o další "rozšířené" funkci

    BOOL DrawIconEx(
      HDC hdc, // handle kontextu zařízení
      int xLeft, // x-ová souřadnice levého horního rohu
      int yTop, // y-ová souřadnice levého horního rohu
      HICON hIcon, // handle ikony
      int cxWidth, // délka ikony
      int cyWidth, // výška ikony
      UINT istepIfAniCur, // index obrázku v animovaném kurzoru
      HBRUSH hbrFlickerFreeDraw, // handle štětce pozadí
      UINT diFlags // volby kreslení
    );

    Tato funkce umožňuje kreslit ikony nebo kurzory, včetně jednotlivých obrázků animovaných kurzorů, jak napovídá parametr istepIfAniCur. Máme dále možnost specifikovat rozměry, do kterých je výsledný obrázek roztažen. Parametr hbrFlickerFreeDraw umožňuje redukovat případné blikání při překreslování ikony nebo kurzoru. Pokud je uveden platný handle na brush (štětec), systém použije tento štětec jako pozadí s tím, že vytvoří v paměti bitmapu s tímto pozadím, do ní nakreslí ikonu nebo kurzor a tuto bitmapu pak přímo kopíruje do kontextu zařízení.

    Použití této funkce vidíte na spodní části dialogu z ukázkového příkladu, kde jsou nakresleny jednotlivé kroky animovaného kurzoru, načteného ze souboru. Celý kód je realizován v handleru zprávy WM_PAINT:

    int xPos, yPos;
    xPos = 20;
    yPos = 200;
    hicon = (HICON)LoadImage(AfxGetInstanceHandle(),
      "anicur.ani", IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED | LR_LOADFROMFILE);
    DrawIconEx(dc.m_hDC, xPos, yPos, hicon, 32, 32, 0, NULL, DI_NORMAL);
    xPos += 50;
    DrawIconEx(dc.m_hDC, xPos, yPos, hicon, 32, 32, 1, NULL, DI_NORMAL);
    xPos += 50;
    DrawIconEx(dc.m_hDC, xPos, yPos, hicon, 32, 32, 2, NULL, DI_NORMAL);
    xPos += 50;
    DrawIconEx(dc.m_hDC, xPos, yPos, hicon, 32, 32, 3, NULL, DI_NORMAL);
    xPos += 50;
    DrawIconEx(dc.m_hDC, xPos, yPos, hicon, 32, 32, 4, NULL, DI_NORMAL);
    xPos += 50;
    DrawIconEx(dc.m_hDC, xPos, yPos, hicon, 32, 32, 5, NULL, DI_NORMAL);

    Na závěr tohoto článku si ještě ukážeme, jak oknu nastavit příslušný kurzor, s tím, že se přesvědčíme o možnosti záměny ikony a kurzoru. Jako kurzor tedy nastavíme ikonu načtenou ze zdrojů. Pro nastavení kurzoru oknu, přesněji řečeno třídě, ke které okno patří, použijme funkci SetClassLongPtr (popř. starší variantu SetClassLong, která však není kompatibilní s 64bitovou verzí Windows). Následující funkce nastaví oknu dialogu jako kurzor ikonu IDR_MAINFRAME s tím, že ji navíc roztáhne do velikosti 64 x 64 pixelů:

    void CUkazkaDlg::OnButton1()
    {
      SetClassLongPtr(m_hWnd, GCLP_HCURSOR,
        (LONG)LoadImage(AfxGetInstanceHandle(),
          MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 64,64, 0));
    }

    Druhá funkce použije jinou ikonu (konkrétně ikonu programu Microsoft Word 2000), načte ji černobíle a přiřadí oknu jako kurzor:

    void CUkazkaDlg::OnButton2()
    {
      SetClassLongPtr(m_hWnd, GCLP_HCURSOR,
        (LONG)LoadImage(AfxGetInstanceHandle(),
          MAKEINTRESOURCE(IDI_ICON2), IMAGE_ICON, 64,64, LR_MONOCHROME));
    }

    Chceme-li vrátit oknu zpět výchozí kurzor, použijeme příslušný systémový kurzor:

    void CUkazkaDlg::OnButton3()
    {
      SetClassLongPtr(m_hWnd, GCLP_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
    }

    Ještě poznámku k "vrácení" výchozího kurzoru: V naší ukázce nastavujeme výchozí systémový kurzor, což v některých případech nemuselo být algoritmicky čisté. Pokud by náš modul byl částí nějakého rozsáhlejšího programu, mohlo by se stát, že dříve, než se nám okno "dostane do spárů", mu byl přiřazen nějaký specifický kurzor, a patřilo by tedy k dobrému vychování vrátit mu zase tento kurzor. Tuto možnost nám dává návratová hodnota funkce SetClassLongPtr, která vrací předchozí hodnotu příslušného parametru třídy, tedy v našem případě handle na kurzor. Znamenalo by to algoritmicky si ošetřit "první sáhnutí na kurzor", uložit si návratovou hodnotu funkce a při "rozloučení se s oknem" tuto hodnotu nastavit zpět jako kurzor.

    Tolik prozatím k ikonám a kurzorům. V některém z příštích článků se můžeme podívat podrobněji na to, jak lze „pracovat“ přímo s daty ikon a kurzorů, získanými ze zdrojů programu.

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

Diskuze (4) Další článek: Spoluzakladatel společnosti Akamai byl v uneseném letadle

Témata článku: Software, Microsoft, Windows, Programování, Brush, Stejný obrázek, Blikání, Více, Kurzor, Icon, Horní okno, Kurz, Ukázkový příklad, Hicon, Funkce, Požadovaná délka


Určitě si přečtěte

Šmírovačka kamerami Googlu: Koukněte se, co nového zachytily na Street View

Šmírovačka kamerami Googlu: Koukněte se, co nového zachytily na Street View

Google stále fotí celý svět do své služby Street View. A novodobou zábavou je hledat v mapách Googlu vtipné záběry. Podívejte se na výběr nejlepších!

redakce | 44

Portál občana už funguje. Na státní web vypadá až překvapivě použitelně

Portál občana už funguje. Na státní web vypadá až překvapivě použitelně

** Portál občana už funguje, vyřídíte na něm první požadavky ** Funkce se budou postupně rozšiřovat ** Web je docela moderní a přehledný

David Polesný | 65

Nová zbraň Microsoftu proti iPadu: Levný tablet Surface Go bude stát jen deset tisíc

Nová zbraň Microsoftu proti iPadu: Levný tablet Surface Go bude stát jen deset tisíc

** Microsoft představil nový tablet Surface Go ** Nový model zaujme nízkou cenou, ale schopnostmi zařízení Surface ** Microsoft nepoužil čip ARM, ale klasický procesor od Intelu 

Karel Javůrek | 116

Byli tam! Důkazy o přistání na Měsíci, Lunochody i čínská sonda jsou vidět z vesmíru

Byli tam! Důkazy o přistání na Měsíci, Lunochody i čínská sonda jsou vidět z vesmíru

** Sonda LRO pořídila z oběžné dráhy Měsíce zajímavé snímky ** Jsou na nich vidět artefakty všech misí programu Apolla, které přistály na povrchu Měsíce ** Jde například o části lunárních modulů, rovery a dokonce i vlajky

Petr Kubala | 60


Aktuální číslo časopisu Computer

Velký test 18 bezdrátových sluchátek

Vše o přechodu na DVB-T2

Procesory AMD opět porážejí Intel

7 NVMe M.2 SSD v přímém souboji