1 / 41

GUI - Úvod

GUI - Úvod. Něco málo teorie Aplikace řízené tokem událostí (Event driven applications) MVC – Model View Controller Win 32 API Okna a zpr á v y. Fronta zpráv. Zpráva. Zpráva. Nové zprávy. Zpráva. Zpráva. Zpráva. Smyčka zpráv. Výběr zprávy. Zpracování zprávy. Odeslání zprávy

deion
Download Presentation

GUI - Úvod

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. GUI - Úvod • Něco málo teorie • Aplikace řízené tokem událostí (Event driven applications) • MVC – Model View Controller • Win 32 API • Okna a zprávy

  2. Fronta zpráv Zpráva Zpráva Nové zprávy Zpráva Zpráva Zpráva Smyčka zpráv Výběr zprávy Zpracování zprávy Odeslání zprávy (dispatch) Aplikace řízené událostmiEvent driven applications • Také Event driven programming • Používá se např. v OS (přerušení) • GUI

  3. MVCModel View Controller • 1979 - Trygve Mikkjel – SmallTalk (Xerox) • SW architektura, která odděluje • Model = Datový model • View = Interface a zobrazení (např. GUI) • Controller = Řídící logika, reakce na události • Použit např. v • MFC • Od QT od release 4 • NeXTStep • Java SWING (?) • Windows Presentation Foundation (WPF) • Podobné MVC • .Net 3.0 (původně WinFX), nativně na Vistách

  4. MVC • Plné čáry – přímé spojení • Čárkované čáry – nepřímé spojení • Jak to funguje • Vstup od uživatele (např. zmáčknutí tlačítka v GUI) • Controller zpracuje uživatelský vstup (handler nebo callback) • zaktualizuje model dle vstupu • View upraví dle modelu svůj vzhled (GUI) • Model by neměl mít přímé povědomí o View(View si získává data od modelu) • Ale může si zaregistrovat akce pro změny položek modelu (Observer, Listener) • Controller nepředává Model přímo View

  5. GUI – okna, zprávy Win 32 API

  6. Okna Literatura a turoriály • Stránky Microsoftu • MSDN • Knihy o Win 32 API • http://www.stromcode.com/modules.php?name=Glowdot_Tutorials&page=1&tid=1&op=view • http://www.winprog.org/tutorial/ • Google :-)

  7. Okna • Všechno je okno • Včetně olvádacích prvků • controls (prvky GUI) - widgety • Prvky GUI mají svůj handle • většina GUI funkcí používá handle • V C definovány typy pro různé handle • Začínají na H – HICON, HBRUSH .... • Také okno je určeno svým handlem • HWND

  8. Okna • Vytvoření okenní aplikace • Hlavní okno • Registrace třídy okna • Vytvoření okna • Zobrazení okna • Zpracování zpráv • Smyčka událostí • Vybíraní zprávy • Dispatching

  9. Oknočásti okna • Každé okna má určité části • Zobrazení daných částí je řízeno • styly okna • typem okna

  10. Registrace třídy okna • Třída okna (myšleno jako druh okna) • Nemá přímou souvislost s OOP • Nezaměňovat s třídami v C++ nebo v C# • Struktura WNDCLASS nebo WNDCLASSEX • Zavolání RegisterClass nebo RegisterClassEx

  11. Registrace třídy okna WNDCLASSEX WndClsEx; WndClsEx.cbSize = sizeof(WNDCLASSEX); WndClsEx.style = CS_HREDRAW | CS_VREDRAW; WndClsEx.lpfnWndProc = WndProcedure; WndClsEx.cbClsExtra = 0; WndClsEx.cbWndExtra = 0; WndClsEx.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW); WndClsEx.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); WndClsEx.lpszMenuName = NULL; WndClsEx.lpszClassName = "MojeTestovaciOkno"; WndClsEx.hInstance = hInstance; WndClsEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&WndClsEx) • ATOM RegisterClassEx(CONST WNDCLASSEX *lpwcx ); • Vrací ATOM • Všimněte si nastavení velikosti struktury • Definice procedury okna

  12. Vytvoření okna HWND CreateWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam ); • Vytvoří okno a vrátí handle na něj nebo NULL • lpClassName může být jméno okna nebo atom třídy • Dostupné třídy oken poskytované přímo Windows • COMBOBOX • EDIT • LISTBOX • MDICLIENT • RichEdit • RICHEDIT_CLASS • SCROLLBAR • STATIC

  13. Zničení okna • Okno se zruší pomocí BOOL DestroyWindow( HWND hWnd // handle to window to destroy ); • Zruší okno • Zruší menu • Zruší timery • Vyprázdní frontu zpráv pro dané okno • Zruší také okna, které jsou vlastněné daným oknem a také child okna

  14. Zobrazení okna • Vytvořené okno zobrazíme BOOL ShowWindow( HWND hWnd, // handle to window int nCmdShow // show state ); nCmdShow – SW_HIDE, SW_SHOW, SW_MAXIMIZE, SW_MINIMIZE, … Pokud se nastavíWS_VISIBLEpři volání CreateWindow, tak se okno automaticky zobrazí • Vytvořené okno necháme vykreslit BOOL UpdateWindow( HWND hWnd // handle to window ); • Překreslí client area (pošle zprávu)

  15. Smyčka událostí • Windows doručují zprávy do fronty událostí • Windows nevolají přímo call back funkce • Aplikace si musí zprávy sama vyzvednout • Je možné filtrovat zprávy • Zprávy je pak možné předat daným call back funkcím

  16. Smyčka událostí • Zpráva je • Definována pomocí ID • integer • Definovány v include souborech (WinUser.h) • Má navíc parametry • wParam typu WPARAM (32-bitový integer na Win32) • lParam typu LPARAM (32-bitový integer na Win32) • Parametry jsou specifické pro danou zprávu a můžou mít různý význam • Lze si nadefinovat i vlastní zprávy

  17. Fronta zpráv Zpráva Zpráva Nové zprávy Zpráva Zpráva Zpráva Smyčka zpráv Výběr zprávy Zpracování zprávy Odeslání zprávy (dispatch) Smyčka událostí Smyčka událostí (zpráv) obecně

  18. Smyčka událostí • Ve Windows se smyčka událostí realizuje takto: BOOL code; while((code=GetMessage(&msg,NULL,0,0))!= 0) { if (code==-1) { // nastala chyba } else { TranslateMessage(&msg); DispatchMessage(&msg); } }

  19. Smyčka událostí BOOL GetMessage( LPMSG lpMsg, // message information HWND hWnd, // handle to window UINT wMsgFilterMin, // first message UINT wMsgFilterMax // last message ); • Pokud žádné zprávy nejsou, tak čéká (blokuje) • Do proměnné lpMsg uloží zprávu určenou pro okno hWnd • hWwnd – handle okna • NULL – zprávy pro jakékoliv okno nebo daný thread • wMsgFilterMin a wMsgFilterMax • Přijme jenom zprávy, jejichž ID jsou v daném rozsahu

  20. Smyčka událostí • Formát zprávy je následující typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; } MSG, *PMSG; • pt – souřadnice kurzoru myši v obrazovkových souřadnicích v době, kdy zpráva byla poslána • time – čas v okamžiku poslání zprávy

  21. Smyčka událostí BOOL GetMessage( LPMSG lpMsg, // message information HWND hWnd, // handle to window UINT wMsgFilterMin, // first message UINT wMsgFilterMax // last message ); • Návratová hodnota je BOOL, ale • Vrátí 0: byla poslána zpráva WM_QUIT • Vráti -1: nastala chyba (dá se zjistit pomocí GetLastError) • Vrátí cokoli jiného: přišla zpráva

  22. Smyčka událostí BOOL PeekMessage( LPMSG lpMsg, // message information HWND hWnd, // handle to window UINT wMsgFilterMin, // first message UINT wMsgFilterMax, // last message UINT wRemoveMsg // removal options ); • Funkce podobná GetMesage, ale pokud nejsou žádné zprávy, tak se hned vrátí • Vrátí 0 pokud nejsou žádné zprávy • Poslední parametr určuje, zda-li se má zpráva z fronty odstranit (GetMesage vždy zprávu odstraní)

  23. Smyčka událostí BOOL TranslateMessage( CONST MSG *lpMsg // message information ); • Přeloží zprávu - virtual-keys -> char • WM_KEYDOWN, WM_KEYUP přeloží na WM_CHAR nebo WM_DEADCHAR • WM_SYSKEYDOWN, WM_SYSKEYUP přeloží na WM_SYSCHAR nebo WM_SYSDEADCHAR • Nemodifikuje danou zprávu – pošle novou zprávu • Vrátí 0, pokud zpráva není přeložena • Vrátí nenulovou hodnotu, pokud byla zpráva přeložena

  24. Smyčka událostí LRESULT DispatchMessage( CONST MSG *lpmsg // message information ); • Doručí zprávu proceduře daného okna • Návratová hodnota je dána návratovou hodnotou okenní procedury • Většinou se ignoruje • Pokud je zpráva typu WM_TIMER a lParam není NULL • lParam obsahuje adresu funkce, která se zavolá místo procedury okna

  25. Smyčka událostí Pořadí zpráv, jak se doručují • Sent messages • Posted messages • Input (hardware) messages and system internal events • Sent messages (again) • WM_PAINT messages • WM_TIMER messages

  26. Poslání zprávy BOOL PostMessage( HWND hWnd, // handle to destination window UINT Msg, // message WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); • Pošle zprávu danému oknu • Zpráva se uloží do smyčky zpráv • Nečeká se na výsledek, program pokračuje hned dále • Vrátí nulu, pokud volání selže

  27. Poslání zprávy LRESULT SendMessage( HWND hWnd, // handle to destination window UINT Msg, // message WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); • Pošle zprávu danému oknu • Zavolá proceduru okna - nejde přes smyčku zpráv • Pokud je okno ze stejného threadu zavolá proceduru přímo (jako podprogram) • Pokud ne, tak je ji potřeba zpracovat v druhém threadu – uloží se do fronty zpráv • Čeká se, dokud zpráva není zpracována

  28. Procedura okna typedef struct _WNDCLASSEX { UINT cbSize; UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; HICON hIconSm; } WNDCLASSEX, *PWNDCLASSEX; • Zadává se při registraci třídy okna pomocí RegisterClassEx • Položka: WNDPROC lpfnWndProc

  29. Procedura okna LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); • Obsluhuje zprávy poslané danému oknu • Většinou implementováno jako velký switch • Pokud procedura okna danou zprávu neobslouží, tak by se měl zavolat standardní handler • return DefWindowProc(hwnd, uMsg, wParam, lParam);

  30. #include <windows.h> LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CLOSE: { DestroyWindow(hwnd); return 0; } case WM_DESTROY:{ PostQuitMessage(0); return 0; } } return DefWindowProc(hwnd, msg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.lpszMenuName = NULL; wc.lpszClassName = "X36APIClass"; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) COLOR_APPWORKSPACE; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) return -1; HWND hwnd=CreateWindowEx(WS_EX_CLIENTEDGE,"X36APIClass","API",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,256, 128,NULL, NULL, hInstance, NULL); if(hwnd==NULL) return -1; ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); BOOL code; MSG msg; while((code=GetMessage(&msg,NULL,0,0))!= 0) { if (code==-1) return -1; TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; }

  31. #include <windows.h> HWND button; LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CLOSE: { DestroyWindow(hwnd); return 0; } case WM_DESTROY:{ PostQuitMessage(0); return 0; } case WM_COMMAND: { if((HWND) lParam==button) MessageBox(NULL,"Clicked!","Hey",MB_OK); return 0; } } return DefWindowProc(hwnd, msg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.lpszMenuName = NULL; wc.lpszClassName = "X36APIClass"; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) COLOR_APPWORKSPACE; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) return -1; HWND hwnd=CreateWindowEx(WS_EX_CLIENTEDGE,"X36APIClass","API",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,256, 128,NULL, NULL, hInstance, NULL); button=CreateWindow("BUTTON","Click!",WS_CHILDWINDOW | WS_VISIBLE | BS_PUSHBUTTON, 10,10,100,25,hwnd, NULL, hInstance, NULL); SetParent(button,hwnd); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); BOOL code; MSG msg; while((code=GetMessage(&msg,NULL,0,0))!= 0) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; }

  32. Dialogy • Součástí aplikace můžou být resources • Lze je definovat v MSVC • Různé typy dat • V programu lze s nimi pracovat

  33. Dialogy • Součástí resource jsou i šablony dialogů • Lze si „naklikat“ dialog v MSVC • Ošetření zpráv se, ale musí udělat ručně (nemluvíme zde o MSFC)

  34. Dialogy HWND CreateDialog( HINSTANCE hInstance, // handle to module LPCTSTR lpTemplate, // dialog box template name HWND hWndParent, // handle to owner window DLGPROC lpDialogFunc // dialog box procedure ); • Každý dialog má okenní proceduru • Má jiný tvar než „normální“ procedura okna • BOOL CALLBACK DialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) • Vrací TRUE pokud byla zpráva zpracována, jinak FALSE • Nesmí se volat DefWindowProc

  35. Dialogy • Pokud používáte dialog z resources • #include "resource.h" • V include souboru jsou konstanty pomocí kterých lze data z reousrces dostat • Makro – MAKEINTRESOURCE(IDD_DIALOG1) • IDD_DIALOG1 = id dialogu CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,DialogProc);

  36. Dialogy • Aby se správně zpracovávaly klávesové zkratky, je potřeba modifikovat hlavní smyčku událostí while((code=GetMessage(&msg,NULL,0,0))!= 0) { if (code==-1) return -1; if(!IsDialogMessage(dialog, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }

  37. Dialogy - příklad • Následující kód vytvoří tento dialog pos stisknutí tlačítka

  38. Dialogy - příklad • Automaticky vygenerovaný soubor resource1.h //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by GUI_HelloWorld1.rc // #define IDD_DIALOG1 101 #define IDC_EDIT1 1004 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1005 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif

  39. Dialogy - příklad • Automaticky vygenerovaný soubor resource1.h • Resource soubor (.rc) je textový soubor, který popisuje dané resources //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by GUI_HelloWorld1.rc // #define IDD_DIALOG1 101 #define IDC_EDIT1 1004 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1005 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif

  40. int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int show) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.lpszMenuName = NULL; wc.lpszClassName = "X36APIClass"; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) COLOR_APPWORKSPACE; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) return -1; HWND hwnd=CreateWindowEx(WS_EX_CLIENTEDGE,"X36APIClass","API",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 256, 128,NULL, NULL, hInstance, NULL); button=CreateWindow("BUTTON","Click!",WS_CHILDWINDOW | WS_VISIBLE | BS_PUSHBUTTON, 10,10,100,25,hwnd, NULL, hInstance, NULL); dialog=CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,DialogProc); SetParent(button,hwnd); ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); BOOL code; MSG msg; while((code=GetMessage(&msg,NULL,0,0))!= 0) { if(code==-1) return -1; if(!IsDialogMessage(dialog, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; }

  41. #include <windows.h> #include "resource1.h" HWND button; HWND dialog=NULL; LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CLOSE: { DestroyWindow(hwnd); return 0; } case WM_DESTROY:{ PostQuitMessage(0); return 0; } case WM_COMMAND: { if((HWND) lParam==button) { ShowWindow(dialog,SW_SHOW); } return 0; } } return DefWindowProc(hwnd, msg, wParam, lParam); } BOOL CALLBACK DialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) { if(uMsg==WM_COMMAND && ((LOWORD(wParam))==IDOK || (LOWORD(wParam))==IDCANCEL)) { ShowWindow(hwndDlg,SW_HIDE); return TRUE; } return FALSE; }

More Related