gui - Úvod

41
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

Upload: deion

Post on 14-Jan-2016

95 views

Category:

Documents


0 download

DESCRIPTION

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 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 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ávy

Page 2: GUI - Úvod

Aplikace řízené událostmiEvent driven applications

• Také Event driven programming– Používá se např. v OS (přerušení)– GUI

Fronta zprávZprávaZprávaZprávaZpráva

Zpráva

Výběr zprávy

Odeslání zprávy

(dispatch)

Smyčkazpráv

Zpracovánízprávy

Novézprávy

Page 3: GUI - Úvod

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

Page 4: GUI - Úvod

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

Page 5: GUI - Úvod

Win 32 API

GUI – okna, zprávy

Page 6: GUI - Úvod

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 :-)

Page 7: GUI - Úvod

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

Page 8: GUI - Úvod

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

Page 9: GUI - Úvod

Oknočásti okna

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

– styly okna– typem okna

Page 10: GUI - Úvod

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

Page 11: GUI - Úvod

Registrace třídy okna

• ATOM RegisterClassEx(CONST WNDCLASSEX *lpwcx );

• Vrací ATOM• Všimněte si nastavení velikosti struktury• Definice procedury 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)

Page 12: GUI - Úvod

Vytvoření okna• 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

HWND CreateWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);

Page 13: GUI - Úvod

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

Page 14: GUI - Úvod

Zobrazení okna

• Vytvořené okno zobrazímeBOOL ShowWindow(

HWND hWnd, // handle to window int nCmdShow // show state);

nCmdShow – SW_HIDE, SW_SHOW, SW_MAXIMIZE, SW_MINIMIZE, …

Pokud se nastaví WS_VISIBLE při volání CreateWindow, tak se okno automaticky zobrazí

• Vytvořené okno necháme vykreslitBOOL UpdateWindow(

HWND hWnd // handle to window);

• Překreslí client area (pošle zprávu)

Page 15: GUI - Úvod

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

Page 16: GUI - Úvod

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

Page 17: GUI - Úvod

Smyčka událostí

Smyčka událostí (zpráv) obecně

Fronta zprávZprávaZprávaZprávaZpráva

Zpráva

Výběr zprávy

Odeslání zprávy

(dispatch)

Smyčkazpráv

Zpracovánízprávy

Novézprávy

Page 18: GUI - Úvod

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); }}

Page 19: GUI - Úvod

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

Page 20: GUI - Úvod

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

Page 21: GUI - Úvod

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

Page 22: GUI - Úvod

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í)

Page 23: GUI - Úvod

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

Page 24: GUI - Úvod

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

Page 25: GUI - Úvod

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

Page 26: GUI - Úvod

Poslání zprávyBOOL 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

Page 27: GUI - Úvod

Poslání zprávyLRESULT 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

Page 28: GUI - Úvod

Procedura oknatypedef 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

Page 29: GUI - Úvod

Procedura oknaLRESULT 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);

Page 30: GUI - Úvod

#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;}

Page 31: GUI - Úvod

#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;}

Page 32: GUI - Úvod

Dialogy

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

Page 33: GUI - Úvod

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)

Page 34: GUI - Úvod

DialogyHWND 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

Page 35: GUI - Úvod

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);

Page 36: GUI - Úvod

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);

}}

Page 37: GUI - Úvod

Dialogy - příklad

• Následující kód vytvoří tento dialog pos stisknutí tlačítka

Page 38: GUI - Úvod

//{{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

Dialogy - příklad

• Automaticky vygenerovaný soubor resource1.h

Page 39: GUI - Úvod

//{{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

Dialogy - příklad

• Automaticky vygenerovaný soubor resource1.h

• Resource soubor (.rc) je textový soubor, který popisuje dané resources

Page 40: GUI - Úvod

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;}

Page 41: GUI - Úvod

#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;

}