sessão 10 – Programação gráfica orientada a eventos (2ª versão)
Referências bibliográficas:
Capítulos 2-5 e 7-9 do Livro Windows NT 4 Programming
MSDN:
Introduction to Windows Programming in C++
https://msdn.microsoft.com/en-us/library/ff381398(v=vs.85).aspx
Mouse Input
https://msdn.microsoft.com/en-us/library/gg153549(v=vs.85).aspx
Keyboard Input
https://msdn.microsoft.com/en-us/library/gg153546(v=vs.85).aspx
Mouse Movement
https://msdn.microsoft.com/en-us/library/gg153550(v=vs.85).aspx
Dialog Boxes
https://msdn.microsoft.com/en-us/library/windows/desktop/ms632588(v=vs.85).aspx
Menus
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646977(v=vs.85).aspx
Windows Graphics Device Interface (GDI)
https://msdn.microsoft.com/en-us/library/dd145203(v=vs.85).aspx
Tutorial online: Win32 Fundamentals
http://www.functionx.com/win32/Lesson01.htm
Events
http://www.functionx.com/win32/Lesson05.htm
Object-Oriented Win32
http://www.functionx.com/win32/Lesson06.htm
Esta é a segunda revisão destes conteúdos (desenhar completo):
#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
//função que vai ser chamada pelo windows sempre que acontece alguma coisa: eventos..
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
TCHAR szProgName[] = TEXT("Base"); //nome da janela
//winMain: main na parte gráfica
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd; // hWnd é o handler da janela, gerado mais abaixo por CreateWindow()
MSG lpMsg; // MSG é uma estrutura definida no Windows para as mensagens
WNDCLASSEX wcApp; // WNDCLASSEX definir as características da classe da janela
//1. caracteristicas da janela
wcApp.cbSize = sizeof(WNDCLASSEX); // Tamanho da estrutura WNDCLASSEX
wcApp.hInstance = hInst;// Instância da janela actualmente exibida
wcApp.lpszClassName = szProgName; // Nome da janela (neste caso = nome do programa)
wcApp.lpfnWndProc = TrataEventos; //indicar a a função que trata eventos
wcApp.style = CS_HREDRAW | CS_VREDRAW; // Estilo da janela: Fazer o redraw se for
// modificada horizontal ou verticalmente
wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION); // "NULL" = Icon definido no Windows
wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION); // "NULL" = Icon definido no Windows
wcApp.hCursor = LoadCursor(NULL, IDC_ARROW); // "hCursor" = handler do cursor (rato)
// "NULL" = Forma definida no Windows
// "IDC_ARROW" Aspecto "seta"
wcApp.lpszMenuName = NULL; // (NULL = não tem menu)
wcApp.cbClsExtra = 0; // Livre, para uso particular
wcApp.cbWndExtra = 0; // Livre, para uso particular
wcApp.hbrBackground = CreateSolidBrush(RGB(0,255,0)); //cor de fundo
// 2. Registar a classe "wcApp" no Windows
if (!RegisterClassEx(&wcApp))
return(0);
// 3. Criar a janela
hWnd = CreateWindow(
szProgName, // Nome da janela (programa) definido acima
TEXT("Estudo para o exame"),// Texto que figura na barra do título
WS_OVERLAPPEDWINDOW, // Estilo da janela (WS_OVERLAPPED= normal)
CW_USEDEFAULT, // Posição x pixels (CW_USEDEFAULT=à direita da última)
CW_USEDEFAULT, // Posição y pixels (CW_USEDEFAULT=abaixo da última)
800, // Largura da janela (em pixels)
600, // Altura da janela (em pixels)
(HWND)HWND_DESKTOP, // handle da janela pai ou HWND_DESKTOP se a janela for a primeira, criada a partir do "desktop"
(HMENU)NULL, // handle do menu da janela (se tiver menu)
(HINSTANCE)hInst,
0);
// 4. Mostrar a janela
ShowWindow(hWnd, nCmdShow); // "hWnd"= handler da janela, devolvido por
// "CreateWindow"; "nCmdShow"= modo de exibição (p.e.
// normal/modal); é passado como parâmetro de WinMain()
UpdateWindow(hWnd); // Refrescar a janela (Windows envia à janela uma mensagem para pintar, mostrar dados, (refrescar)…
// 5. Loop de Mensagens
while (GetMessage(&lpMsg, NULL, 0, 0)) {
TranslateMessage(&lpMsg); // pre processar os eventos
DispatchMessage(&lpMsg); //
} //GetMessage se recebe zero, fechar a janela, sai do ciclo
// 6. Fim do programa
return((int)lpMsg.wParam); // Retorna sempre o parâmetro wParam da estrutura lpMsg
}
int contaCliques =0;
typedef struct
{
int xPos, yPos;
TCHAR c;
} PosicaoCaracter;
LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
// UINT messg: código do evento de carregar numa tecla
// valor da tecla que foi carregada é do WPARAM wParam
// lParam: posixaoX, posicaoY do rato na janela
static TCHAR c = '?'; //ou global
//static int posX = 0; //ou static ou global, com o BeginPaint
//static int posY = 0; //ou static ou global, com o BeginPaint
HDC hdc; //para a escrita em janela!, handle device content
RECT rect; //espaço de desenho
static TCHAR charValue = '?';
PAINTSTRUCT ps;
//array dos histórico das posicções
static PosicaoCaracter posicoes[500];
static int totoalPosicoes = 0;
int i;
switch (messg) {
case WM_PAINT: //evento para refresh da janela
//operação de escrita REAL na janela é aqui
hdc= BeginPaint(hWnd, &ps); //substitui GetDC(hWnd);
// a posição da escrita
GetClientRect(hWnd, &rect);
FillRect(hWnd, &rect, CreateSolidBrush(RGB(0, 255, 0))); //pintar funto controlado
SetTextColor(hdc, RGB(0, 123, 0));
//fundo transparente
SetBkColor(hdc, TRANSPARENT);
for(i=0; i < totoalPosicoes; i++){
rect.left = posicoes[i].xPos;
rect.top = posicoes[i].yPos;
//escrita do texto
DrawText(hdc, &posicoes[i].c, 1, &rect, DT_SINGLELINE | DT_NOCLIP);
}
EndPaint(hWnd, &ps); //substitui ReleaseDC(hWnd, hdc);
break;
//case WM_ERASEBKGND: //somos nós a tratar o BKRND
// return TRUE;
case WM_CHAR:
c = (TCHAR)wParam;
break;
case WM_LBUTTONDOWN:
contaCliques++;
charValue = contaCliques + '0';
break;
case WM_RBUTTONDOWN:
if(totoalPosicoes < 500){
posicoes[totoalPosicoes].xPos = GET_X_LPARAM(lParam); //macro GET_X_LPARAM
posicoes[totoalPosicoes].yPos = GET_Y_LPARAM(lParam);//macro GET_Y_LPARAM
posicoes[totoalPosicoes].c = charValue;
totoalPosicoes++;
InvalidateRect(hWnd, NULL, FALSE); //janela invalida, pinta de novo
}
//limpar a janela com o beginpaint
//inicio processo desenhar/escrever
//hdc = GetDC(hWnd);
//fim processo desenhar/escrever
//ReleaseDC(hWnd, hdc);
break;
case WM_CLOSE: //fechar a janela
if(
MessageBox(
hWnd,
TEXT("tem a certeza que quer sair?"),
TEXT("Confirmação"),
MB_YESNO | MB_ICONQUESTION) //combinar flags |
== IDYES)
{
DestroyWindow(hWnd);
//fechar a janela
}
break;
case WM_DESTROY: // Destruir a janela e terminar o programa
PostQuitMessage(0); // "PostQuitMessage(Exit Status)"
break;
default: //mt importante, para lidar com o que não foi feito tratamento
return(DefWindowProc(hWnd, messg, wParam, lParam));
break; // break tecnicamente desnecessário por causa do return
}
return(0);
}
Esta é a segunda revisão destes conteúdos (desenhar completo e limpo):
#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
TCHAR szProgName[] = TEXT("Base");
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
MSG lpMsg;
WNDCLASSEX wcApp;
wcApp.cbSize = sizeof(WNDCLASSEX);
wcApp.hInstance = hInst;
wcApp.lpszClassName = szProgName;
wcApp.lpfnWndProc = TrataEventos;
wcApp.style = CS_HREDRAW | CS_VREDRAW;
wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION);
wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);
wcApp.lpszMenuName = NULL;
wcApp.cbClsExtra = 0;
wcApp.cbWndExtra = 0;
wcApp.hbrBackground = CreateSolidBrush(RGB(0,255,0));
if (!RegisterClassEx(&wcApp))
return(0);
hWnd = CreateWindow(
szProgName,
TEXT("Estudo para o exame"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
(HWND)HWND_DESKTOP,
(HMENU)NULL,
(HINSTANCE)hInst,
0);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&lpMsg, NULL, 0, 0)) {
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
return((int)lpMsg.wParam);
}
int contaCliques =0;
typedef struct
{
int xPos, yPos;
TCHAR c;
} PosicaoCaracter;
LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
static TCHAR c = '?';
HDC hdc;
RECT rect;
static TCHAR charValue = '?';
PAINTSTRUCT ps;
static PosicaoCaracter posicoes[500];
static int totoalPosicoes = 0;
int i;
switch (messg) {
case WM_PAINT:
hdc= BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rect);
FillRect(hWnd, &rect, CreateSolidBrush(RGB(0, 255, 0)));
SetTextColor(hdc, RGB(0, 123, 0));
SetBkColor(hdc, TRANSPARENT);
for(i=0; i < totoalPosicoes; i++){
rect.left = posicoes[i].xPos;
rect.top = posicoes[i].yPos;
DrawText(hdc, &posicoes[i].c, 1, &rect, DT_SINGLELINE | DT_NOCLIP);
}
EndPaint(hWnd, &ps);
break;
case WM_CHAR:
c = (TCHAR)wParam;
break;
case WM_LBUTTONDOWN:
contaCliques++;
charValue = contaCliques + '0';
break;
case WM_RBUTTONDOWN:
if(totoalPosicoes < 500){
posicoes[totoalPosicoes].xPos = GET_X_LPARAM(lParam);
posicoes[totoalPosicoes].yPos = GET_Y_LPARAM(lParam);
posicoes[totoalPosicoes].c = charValue;
totoalPosicoes++;
InvalidateRect(hWnd, NULL, FALSE);
}
break;
case WM_CLOSE:
if(
MessageBox(
hWnd,
TEXT("tem a certeza que quer sair?"),
TEXT("Confirmação"),
MB_YESNO | MB_ICONQUESTION)
== IDYES)
{
DestroyWindow(hWnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, messg, wParam, lParam));
break;
}
return(0);
}
Usar uma BMP na janela (segunda versão):
#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
//exercicio 6)
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
TCHAR szProgName[] = TEXT("Base");
//lidar com o bitmap, globais: têm que ser acedidas por várias funções, ou uma struct 1 uma variavel global
HBITMAP hBMP; //acesso ao bitmap
HDC bmpDC;
BITMAP bmp; //estrutura do bitmap
int xBitmap;
int yBitmap;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
MSG lpMsg;
WNDCLASSEX wcApp;
wcApp.cbSize = sizeof(WNDCLASSEX);
wcApp.hInstance = hInst;
wcApp.lpszClassName = szProgName;
wcApp.lpfnWndProc = TrataEventos;
wcApp.style = CS_HREDRAW | CS_VREDRAW;
wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION);
wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);
wcApp.lpszMenuName = NULL;
wcApp.cbClsExtra = 0;
wcApp.cbWndExtra = 0;
wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));
if (!RegisterClassEx(&wcApp))
return(0);
hWnd = CreateWindow(
szProgName,
TEXT("Estudo para o exame"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
(HWND)HWND_DESKTOP,
(HMENU)NULL,
(HINSTANCE)hInst,
0);
//lidar com o bitmap
hBMP = (HBITMAP)LoadImage(NULL, TEXT("imagem.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
//preciso da informação da imagem (metadados)
GetObject(hBMP, sizeof(bmp), &bmp);
//passar a informação para o device content
HDC hdc;
hdc = GetDC(hWnd);
//criar a copia
bmpDC = CreateCompatibleDC(hdc);
//aplicar o bitmap ao DC
SelectObject(bmpDC, hBMP);
ReleaseDC(hWnd, hdc);
//definir as posições iniciais da imagem: ao centro
RECT rect; //largura da janela actual do cliente
GetClientRect(hWnd, &rect);
//xBitmap = (rect.right / 2) - (bmp.bmWidth / 2);
//yBitmap = (rect.bottom / 2) - (bmp.bmHeight / 2);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&lpMsg, NULL, 0, 0)) {
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
return((int)lpMsg.wParam);
}
LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
HDC hdc;
RECT rect;
PAINTSTRUCT ps;
switch (messg) {
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rect);
FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0)));
//SetTextColor(hdc, RGB(0, 123, 0));
//SetBkColor(hdc, TRANSPARENT);
//desenhar
BitBlt(hdc, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
//lidar com o resize da janela
//LOWORD(lParam) -> parte menos significativa, largura
xBitmap = (LOWORD(lParam) / 2) - (bmp.bmWidth / 2);
//LOWORD(lParam) -> parte mais significativa, altura
yBitmap = (HIWORD(lParam) / 2) - (bmp.bmHeight / 2);
break;
case WM_CLOSE:
if (
MessageBox(
hWnd,
TEXT("tem a certeza que quer sair?"),
TEXT("Confirmação"),
MB_YESNO | MB_ICONQUESTION)
== IDYES)
{
DestroyWindow(hWnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, messg, wParam, lParam));
break;
}
return(0);
}
Usar um BMP animado na janela (segunda versão):
#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
//exercicio 6)
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
TCHAR szProgName[] = TEXT("Base");
//lidar com o bitmap, globais: têm que ser acedidas por várias funções, ou uma struct 1 uma variavel global
HBITMAP hBMP; //acesso ao bitmap
HDC bmpDC;
BITMAP bmp; //estrutura do bitmap
int xBitmap;
int yBitmap;
//lidar com a animção
int limDireito;
HWND hWndGlobalJanela;
DWORD WINAPI MovimentaImagem(LPVOID lParam)
{
int direcaoMovimento = 1; // 1: direita, -1: esquerda
int saltoPixeis = 2;
while (1)
{
xBitmap = xBitmap + (direcaoMovimento)*saltoPixeis;
if (xBitmap <= 0)
{
xBitmap = 0;
direcaoMovimento = 1;
}
else if (xBitmap >= limDireito)
{
xBitmap = limDireito;
direcaoMovimento = -1;
}
//nova pintua da janela: avisar o SO
InvalidateRect(hWndGlobalJanela, NULL, FALSE);
Sleep(10);
}
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
MSG lpMsg;
WNDCLASSEX wcApp;
wcApp.cbSize = sizeof(WNDCLASSEX);
wcApp.hInstance = hInst;
wcApp.lpszClassName = szProgName;
wcApp.lpfnWndProc = TrataEventos;
wcApp.style = CS_HREDRAW | CS_VREDRAW;
wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION);
wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);
wcApp.lpszMenuName = NULL;
wcApp.cbClsExtra = 0;
wcApp.cbWndExtra = 0;
wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));
if (!RegisterClassEx(&wcApp))
return(0);
hWnd = CreateWindow(
szProgName,
TEXT("Estudo para o exame"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
(HWND)HWND_DESKTOP,
(HMENU)NULL,
(HINSTANCE)hInst,
0);
//lidar com o bitmap
hBMP = (HBITMAP)LoadImage(NULL, TEXT("imagem.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
//preciso da informação da imagem (metadados)
GetObject(hBMP, sizeof(bmp), &bmp);
//passar a informação para o device content
HDC hdc;
hdc = GetDC(hWnd);
//criar a copia
bmpDC = CreateCompatibleDC(hdc);
//aplicar o bitmap ao DC
SelectObject(bmpDC, hBMP);
ReleaseDC(hWnd, hdc);
//definir as posições iniciais da imagem: ao centro
RECT rect; //largura da janela actual do cliente
GetClientRect(hWnd, &rect);
//xBitmap = (rect.right / 2) - (bmp.bmWidth / 2);
//yBitmap = (rect.bottom / 2) - (bmp.bmHeight / 2);
//para o MovimentaImagem
limDireito = rect.right - bmp.bmWidth;
hWndGlobalJanela = hWnd;
CreateThread(NULL, 0, MovimentaImagem, NULL, 0, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&lpMsg, NULL, 0, 0)) {
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
return((int)lpMsg.wParam);
}
LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
HDC hdc;
RECT rect;
PAINTSTRUCT ps;
switch (messg) {
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rect);
FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0)));
//SetTextColor(hdc, RGB(0, 123, 0));
//SetBkColor(hdc, TRANSPARENT);
//desenhar
BitBlt(hdc, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
//lidar com o resize da janela
//LOWORD(lParam) -> parte menos significativa, largura
xBitmap = (LOWORD(lParam) / 2) - (bmp.bmWidth / 2);
//LOWORD(lParam) -> parte mais significativa, altura
yBitmap = (HIWORD(lParam) / 2) - (bmp.bmHeight / 2);
//a ver com a animação, update
limDireito = LOWORD(lParam) - bmp.bmWidth;
break;
case WM_CLOSE:
if (
MessageBox(
hWnd,
TEXT("tem a certeza que quer sair?"),
TEXT("Confirmação"),
MB_YESNO | MB_ICONQUESTION)
== IDYES)
{
DestroyWindow(hWnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, messg, wParam, lParam));
break;
}
return(0);
}
Esta é a segunda revisão destes conteúdos (desenhar animado e lidar com a concorrência):
#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
//exercicio 6)
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
TCHAR szProgName[] = TEXT("Base");
//lidar com o bitmap, globais: têm que ser acedidas por várias funções, ou uma struct 1 uma variavel global
HBITMAP hBMP; //acesso ao bitmap
HDC bmpDC;
BITMAP bmp; //estrutura do bitmap
int xBitmap;
int yBitmap;
//lidar com a animação
int limDireito;
HWND hWndGlobalJanela;
//concorrencia, problema de sincronização
HANDLE hMutex;
DWORD WINAPI MovimentaImagem(LPVOID lParam)
{
int direcaoMovimento = 1; // 1: direita, -1: esquerda
int saltoPixeis = 2;
while (1)
{
WaitForSingleObject(hMutex, INFINITE); //problema de sincronização
xBitmap = xBitmap + (direcaoMovimento)*saltoPixeis;
if (xBitmap <= 0)
{
xBitmap = 0;
direcaoMovimento = 1;
}
else if (xBitmap >= limDireito)
{
xBitmap = limDireito;
direcaoMovimento = -1;
}
ReleaseMutex(hMutex);
//nova pintua da janela: avisar o SO
InvalidateRect(hWndGlobalJanela, NULL, FALSE);
Sleep(10);
}
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
MSG lpMsg;
WNDCLASSEX wcApp;
wcApp.cbSize = sizeof(WNDCLASSEX);
wcApp.hInstance = hInst;
wcApp.lpszClassName = szProgName;
wcApp.lpfnWndProc = TrataEventos;
wcApp.style = CS_HREDRAW | CS_VREDRAW;
wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION);
wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);
wcApp.lpszMenuName = NULL;
wcApp.cbClsExtra = 0;
wcApp.cbWndExtra = 0;
wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));
if (!RegisterClassEx(&wcApp))
return(0);
hWnd = CreateWindow(
szProgName,
TEXT("Estudo para o exame"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
(HWND)HWND_DESKTOP,
(HMENU)NULL,
(HINSTANCE)hInst,
0);
//lidar com o bitmap
hBMP = (HBITMAP)LoadImage(NULL, TEXT("imagem.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
//preciso da informação da imagem (metadados)
GetObject(hBMP, sizeof(bmp), &bmp);
//passar a informação para o device content
HDC hdc;
hdc = GetDC(hWnd);
//criar a copia
bmpDC = CreateCompatibleDC(hdc);
//aplicar o bitmap ao DC
SelectObject(bmpDC, hBMP);
ReleaseDC(hWnd, hdc);
//definir as posições iniciais da imagem: ao centro
RECT rect; //largura da janela actual do cliente
GetClientRect(hWnd, &rect);
//xBitmap = (rect.right / 2) - (bmp.bmWidth / 2);
//yBitmap = (rect.bottom / 2) - (bmp.bmHeight / 2);
//para o MovimentaImagem
limDireito = rect.right - bmp.bmWidth;
hWndGlobalJanela = hWnd;
hMutex = CreateMutex(NULL, FALSE, NULL);
CreateThread(NULL, 0, MovimentaImagem, NULL, 0, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&lpMsg, NULL, 0, 0)) {
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
return((int)lpMsg.wParam);
}
LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
HDC hdc;
RECT rect;
PAINTSTRUCT ps;
switch (messg) {
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rect);
FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0)));
//SetTextColor(hdc, RGB(0, 123, 0));
//SetBkColor(hdc, TRANSPARENT);
//desenhar
WaitForSingleObject(hMutex, INFINITE); //problema de sincronização
BitBlt(hdc, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
ReleaseMutex(hMutex);
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
//lidar com o resize da janela
//LOWORD(lParam) -> parte menos significativa, largura
WaitForSingleObject(hMutex, INFINITE); //problema de sincronização
xBitmap = (LOWORD(lParam) / 2) - (bmp.bmWidth / 2);
ReleaseMutex(hMutex);
//LOWORD(lParam) -> parte mais significativa, altura
yBitmap = (HIWORD(lParam) / 2) - (bmp.bmHeight / 2);
//a ver com a animação, update
limDireito = LOWORD(lParam) - bmp.bmWidth;
break;
case WM_CLOSE:
if (
MessageBox(
hWnd,
TEXT("tem a certeza que quer sair?"),
TEXT("Confirmação"),
MB_YESNO | MB_ICONQUESTION)
== IDYES)
{
DestroyWindow(hWnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, messg, wParam, lParam));
break;
}
return(0);
}
Esta é a segunda revisão destes conteúdos (desenhar animado e lidar com a concorrência e lidar com a flickering cintilação) com uso do doubleBuffering:
#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
//exercicio 6)
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
TCHAR szProgName[] = TEXT("Base");
HBITMAP hBMP;
HDC bmpDC;
BITMAP bmp;
int xBitmap;
int yBitmap;
int limDireito;
HWND hWndGlobalJanela;
HANDLE hMutex;
//1) lidar com o flickering
HDC memDC = NULL;
HBITMAP hCopiaBMP; //copiar as caracteristicas
DWORD WINAPI MovimentaImagem(LPVOID lParam)
{
int direcaoMovimento = 1;
int saltoPixeis = 2;
while (1)
{
WaitForSingleObject(hMutex, INFINITE);
xBitmap = xBitmap + (direcaoMovimento)*saltoPixeis;
if (xBitmap <= 0)
{
xBitmap = 0;
direcaoMovimento = 1;
}
else if (xBitmap >= limDireito)
{
xBitmap = limDireito;
direcaoMovimento = -1;
}
ReleaseMutex(hMutex);
InvalidateRect(hWndGlobalJanela, NULL, FALSE);
Sleep(10);
}
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
MSG lpMsg;
WNDCLASSEX wcApp;
wcApp.cbSize = sizeof(WNDCLASSEX);
wcApp.hInstance = hInst;
wcApp.lpszClassName = szProgName;
wcApp.lpfnWndProc = TrataEventos;
wcApp.style = CS_HREDRAW | CS_VREDRAW;
wcApp.hIcon = LoadIcon(NULL, IDI_INFORMATION);
wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);
wcApp.lpszMenuName = NULL;
wcApp.cbClsExtra = 0;
wcApp.cbWndExtra = 0;
wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));
if (!RegisterClassEx(&wcApp))
return(0);
hWnd = CreateWindow(
szProgName,
TEXT("Estudo para o exame"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
(HWND)HWND_DESKTOP,
(HMENU)NULL,
(HINSTANCE)hInst,
0);
hBMP = (HBITMAP)LoadImage(NULL, TEXT("imagem.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
GetObject(hBMP, sizeof(bmp), &bmp);
HDC hdc;
hdc = GetDC(hWnd);
bmpDC = CreateCompatibleDC(hdc);
SelectObject(bmpDC, hBMP);
ReleaseDC(hWnd, hdc);
RECT rect;
GetClientRect(hWnd, &rect);
limDireito = rect.right - bmp.bmWidth;
hWndGlobalJanela = hWnd;
hMutex = CreateMutex(NULL, FALSE, NULL);
CreateThread(NULL, 0, MovimentaImagem, NULL, 0, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&lpMsg, NULL, 0, 0)) {
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
return((int)lpMsg.wParam);
}
LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
HDC hdc;
RECT rect;
PAINTSTRUCT ps;
switch (messg) {
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rect);
//2) lidar com o flickering
if(memDC == NULL)
{
//primeiro vez que estou a passar pela memoria
//criar a cópia
memDC = CreateCompatibleDC(hdc);
hCopiaBMP = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
SelectObject(memDC, hCopiaBMP);
DeleteObject(hCopiaBMP);
}
//3) usar a copia em memoria e nao na principal
//FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0)));
FillRect(memDC, &rect, CreateSolidBrush(RGB(0, 255, 0)));
WaitForSingleObject(hMutex, INFINITE);
//BitBlt(hdc, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
BitBlt(memDC, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
ReleaseMutex(hMutex);
//4) escrever a copia em memoria e aplicar na totalidade da janela
BitBlt(hdc, 0, 0, rect.right, rect.bottom, memDC, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
WaitForSingleObject(hMutex, INFINITE);
xBitmap = (LOWORD(lParam) / 2) - (bmp.bmWidth / 2);
yBitmap = (HIWORD(lParam) / 2) - (bmp.bmHeight / 2);
limDireito = LOWORD(lParam) - bmp.bmWidth;
//5) para obrigar a entrar no if no WM_PAINT
ReleaseDC(hWnd, memDC);
memDC = NULL;
ReleaseMutex(hMutex);
break;
case WM_CLOSE:
if (
MessageBox(
hWnd,
TEXT("tem a certeza que quer sair?"),
TEXT("Confirmação"),
MB_YESNO | MB_ICONQUESTION)
== IDYES)
{
DestroyWindow(hWnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, messg, wParam, lParam));
break;
}
return(0);
}


0 thoughts on “sessão 10 – Programação gráfica orientada a eventos (2ª versão)”