Učíme se Win API - 4. - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



C/C++

Učíme se Win API - 4.

winapi_logo

28. ledna 2002, 00.00 | V tomto pokračování se již dočkáme spuštění kompletní, byť té nejjednodušší aplikace, která má všechny základní náležitosti programu pro Windows.

Minulý článek jsme zakončili vytvořením hlavního okna aplikace pomocí funkce CreateWindowEx o které si nyní řekneme trochu podrobněji.

HWND CreateWindowEx(
  DWORD  dwExStyle // rozšířený styl
  LPCTSTR  lpClassName  // jméno registrované třídy okna
  LPCTSTR  lpWindowName  // jméno okna
  DWORD  dwStyle  // styl okna
  int  x  // horizontalní souřadnice
  int  y  // vertikální souřadnice
  int  nWidth // šířka okna
  int  nHeight // výška okna
  HWND  hWndParent  // handle okna předka
  HMENU  hMenu  // handle menu nebo identifikátor prvku
  HINSTANCE  hInstance  // handle instance
  LPVOID  lpParam  // data okna
);

dwExStyle - rozšířený styl. Tímto parametrem se tato funkce liší od své starší předchůdkyně CreateWindow. Spolu s Win32 totiž přibylo několik nových stylů a z důvodu zpětné kompatibility kódu nebylo možné rozšířit počet parametrů funkce CreateWindow, proto byla vytvořena tato rozšířená funkce. Podobných dvojic funkcí existuje více ze stejného důvodu. Úplný výčet možných hodnot je v dokumentaci, řekněme si například, že hodnota WS_EX_TOPMOST specifikuje, že okno bude "vždy navrchu".

lpClassName - jméno registrované třídy, ke které má okno náležet. Může to být některá systémová třída, jako "BUTTON", "LISTBOX" apod. nebo třída zaregistrovaná naší aplikací.

lpWindowName - jméno (text) okna. Každé okna má nějaký text okna (může být samozřejmě "prázdný"), který se u některých typů oken zobrazí. U běžného hlavního okna se tento text zobrazí v titulkovém pruhu, u tlačítka je to jeho "popisek", u edit-boxu jeho vlastní obsah apod.

dwStyle - styl okna. Parametr, resp. kombinace příznaků určujících vlastnosti okna, jako například, zda má hlavní nabídku, které ze systémových ikony, zda jej lze roztahovat tažením za okraj a pod. V našem případě jsme použili hodnotu WS_OVERLAPPEDWINDOW, která představuje okno "se všemi náležitostmi", tedy roztažitelným okrajem, systémovými ikonami v titulkovém pruhu atd. Postupně si ukážeme jak modifikovat vlastnosti okna.

x, y - souřadnice levého horního rohu okna na obrazovce.

nWidth - šířka okna

nHeight - výška okna

hwndParent - handle okna předka ("rodičovské okno"). Týká se to především prvků jako edit, button apod. které jsou umístěny na jiném "běžném" okně. V případě hlavního okna aplikace samozřejmě zadáme hodnotu NULL.

hMenu - handle menu nebo identifikátor okna potomka. U hlavního okna aplikace můžeme zde nastavit hlavní menu aplikace. Pokud je toto menu určeno při registraci třídy, můžeme nechat NULL. O vytvoření menu si samozřejmě řekneme později. Pokud jde o "dětské" okno, typicky již zmíněné buttony nebo edit-boxy, pak zde můžeme uvést identifikátor tohoto prvku, který nám pak umožní při přijímání zpráv od těchto prvků tyto prvky rozlišit. Ale jak uvidíme, identifikátor není nutné používat, i když hlavně u dialogů, je to běžné, prvky budeme moci rozlišit i s použitím handle.

hInstance - handle instance, které dostaneme jako 1. parametr funkce WinMain

lpParam - ukazatel na případná další data, která mohou být vytvořena spolu s oknem. Pokud vytvořené okna má být MDI oknem, tato data obsahují adresu struktury MDICREATESTRUCT, obsahující vlastnosti MDI okna.

Tolik tedy zatím k funkci CreateWindowEx. A nyní se dostáváme k poslední základní části Win32 programu, kterou je procedura okna. Když jsme si popisovali smyčku zpráv, říkali jsme si o funkci DispatchMessage. Tato funkce posílá zprávy vyjmuté ze smyčky zpráv aplikace do procedury příslušného okna, neboť ve frontě zpráv jsou zprávy náležící všem oknům aplikace, ale v proceduře okna pouze zprávy náležící oknu nebo oknům, patřícím k té třídě, která si tuto proceduru okna "zaregistrovala". Procedura okna má následující tvar:

LRESULT CALLBACK WindowProc(
  HWND  hwnd  // handle okna
  UINT   uMsg  // message identifier
  WPARAM  wParam  // 1. parametr zprávy
  LPARAM  lParam  // 2. parametr zprávy
);

hwnd - handle okna. Tento parametr potřebujeme, pokud máme více oken patřících stejné třídě, které mají společnou proceduru okna. V tom případě nám tento parametr určí, kterému z těchto oken je příslušná zpráva určena.

uMsg - identifikátor zprávy. Jedna z hodnot, definovaných v standardních hlavičkových souborech Windows (většinou ve <windows.h>), určující o jakou zprávu se jedná. Například již zmíněné zprávy WM_QUIT nebo WM_LBUTTONDOWN.

wParam - 1. parametr zprávy, 32-ti bitové číslo nesoucí informace specifické pro danou zprávu.

lParam - 2. parametr zprávy, stejně jako wParam 32-ti bitové číslo, které může obsahovat další informace.

Přidejme si nyní do našeho programu následující "minimální" implementaci procedury okna:

LRESULT CALLBACK WindowProcMain(HWND hwnd, UINT uMsg, WPARAM wParam,
                  LPARAM lParam)
{
  switch ( uMsg )
  {
    case WM_DESTROY:
      PostQuitMessage(0);
      break;
  }
  return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

Jak již asi tušíte, podstata zpracování zpráv v proceduře okna spočívá v tom, že zprávy, na které chceme nějak reagovat, zachytáváme v jednom více či méně obsáhlém příkazu switch. Všechny zprávy (včetně těch, na které nějak reagujeme), s výjimkou případů, kdy chceme z nějakého důvodu některou zprávu zadržet, musíme odeslat k výchozímu zpracování pomocí funkce DefWindowProc. Tato funkce má stejnou strukturu jako procedura okna (WindowProc), což pro nás znamená jednoduše předat parametry získané v proceduře okna této funkci.

Dále ve výpisu kódu vidíte, že ve "filtru zpráv" máme uvedenou jedinou zprávu, kterou je WM_DESTROY. Tato zpráva je poslána oknu jako jakési "poslední rozloučení". Znamená, že okno je právě rušeno a v okamžiku doručení zprávy je již odstraněno z obrazovky. Jako reakci na tuto zprávu musíme do smyčky zpráv "ručně" vložit zprávu WM_QUIT. Toto nenjednodušším způsobem realizujeme funkcí PostQuitMessage, jejímž jediným parametrem je návratový kód, který chceme nastavit. Tento kód je pak parametrem wParam zprávy WM_QUIT a ve smyčce zpráv bychom jej mohli získat jako prvek wParam struktury MSG, kterou nám naplní funkce GetMessage ve smyčce zpráv.

A nyní konečně máme kompletní ten nejednodušší kód, realizující skutečnou Win32 aplikaci s hlavním oknem, které má všechny náležitosti běžného okna Windows. Samozřejmě nemá vlastní specifickou ikonu, menu ani žádné další prvky, jako třeba edit-box pro vstup textu apod. Po spuštění dostaneme takovýto výsledek:

Uvedu zde ještě pro přehlednost úplný výpis kódu:

#include "main.h"

#define _MainClassName TEXT("WinAPIMainClass")
#define _AppName TEXT("Učíme se WinAPI")


HINSTANCE g_hInstance;
HWND g_hwndMain;

LRESULT CALLBACK WindowProcMain(HWND hwnd, UINT uMsg, WPARAM wParam, 
                  LPARAM lParam)
{
  switch ( uMsg )
  {
    case WM_DESTROY:
      PostQuitMessage(0);
      break;
  }
  return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

BOOL InitApp()
{
  WNDCLASSEX wc;
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  wc.hInstance = g_hInstance;
  wc.lpfnWndProc = WindowProcMain;
  wc.lpszClassName = _MainClassName;
  wc.lpszMenuName = NULL;
  wc.style = CS_HREDRAW | CS_VREDRAW;
  if ( !RegisterClassEx(&wc) )
    return FALSE;

  g_hwndMain = CreateWindowEx(0, _MainClassName,
    _AppName,
    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    100, 100, 450, 350,
    NULL, NULL, g_hInstance, NULL);
  if ( g_hwndMain == NULL )
    return FALSE;
  return TRUE;
}

MSG msg;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, 
                    LPSTR lpCmdLine, int nShow)
{
  if ( !InitApp() )
    return FALSE;
  g_hInstance = hInstance;
  while ( GetMessage(&msg, NULL, 0, 0) )
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

Příště budeme náš program postupně dále rozvíjet. Řekneme si něco o UNICODE (s tím souvisí makro TEXT použité v kódu), ukážeme si jak vypisovat text přímo na plochu okna -  seznámíme se tedy s GDI, grafickým rozhraním Windows.

Zde je ke stažení projekt (Visual C++ 6) v aktuální fázi vývoje, který ukazuje výše uvedený výpis kódu: win_api_4.zip.


Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » C/C++  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: