Tag: SO2 – 2021 – Ficha 8 v.2.7 – Interface Grafica em Win32.pdf
sessão 11 – 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, usar os recursos do win32 GDI:
1) adicionar recurso
2) escolher Icon
e apagar todos.. e ficar só com um.
3) aceder ao ID do recurso, e alterar para IDI_ICON_APP
4) adicionar um menu, com duas opções fixas e uma opção com submenus
o login, com popup a FALSE
e atribuir os ID a cada uma das opções.
5) as caixas de dialogo
e os componentes para a caixa de diálogo:
6) atalhos de teclas, aceleradores no windows
7) string table
ter um texto configurável, num recurso à parte. Utilidade: internacionalização da aplicação (tradução)
7) pointer
8) os comportamentos, usar o seguinte:
#include <windows.h>
#include <Windowsx.h>
#include <tchar.h>
#include "resource.h"
#define NUM_CLIENTES 3
#define LIST_SIZE 8
TCHAR* LIST_ITENS[] = {
TEXT("10€"),
TEXT("20€"),
TEXT("40€"),
TEXT("60€"),
TEXT("80€"),
TEXT("100€"),
TEXT("150€"),
TEXT("200€")
};
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLogin(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLevantar(HWND, UINT, WPARAM, LPARAM);
TCHAR szProgName[] = TEXT("Ficha8");
typedef struct {
unsigned int ID;
TCHAR username[16];
TCHAR password[16];
unsigned int saldo;
} cliente;
typedef struct {
unsigned int tipo; // 1 = depósito, 2 = levantamento
unsigned int quantia;
unsigned int ID;
} operacao;
typedef struct {
cliente clientes[NUM_CLIENTES];
operacao historico[200];
unsigned int numOperacoes;
} dados;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
HWND hWnd;
MSG lpMsg;
WNDCLASSEX wcApp;
HANDLE hAccel;
dados dadosPartilhados;
wcApp.cbSize = sizeof(WNDCLASSEX);
wcApp.hInstance = hInst;
wcApp.lpszClassName = szProgName;
wcApp.lpfnWndProc = TrataEventos;
wcApp.style = CS_HREDRAW | CS_VREDRAW;
wcApp.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP));
wcApp.hIconSm = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP));
wcApp.hCursor = LoadCursor(hInst, MAKEINTRESOURCE(IDC_POINTER));
wcApp.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_PRINCIPAL);
wcApp.cbClsExtra = sizeof(dados);
wcApp.cbWndExtra = 0;
wcApp.hbrBackground = CreateSolidBrush(RGB(220, 220, 220));
if (!RegisterClassEx(&wcApp))
return(0);
hWnd = CreateWindow(
szProgName,
TEXT("SO2 - Ficha 8"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
300,
150,
(HWND)HWND_DESKTOP,
(HMENU)NULL,
(HINSTANCE)hInst,
0);
dadosPartilhados.numOperacoes = 5; // Apenas para testar...
LONG_PTR x = SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)&dadosPartilhados);
ShowWindow(hWnd, nCmdShow);
hAccel = LoadAccelerators(NULL, MAKEINTRESOURCE(IDR_ACCELERATOR));
while (GetMessage(&lpMsg, NULL, 0, 0))
{
if (!TranslateAccelerator(hWnd, hAccel, &lpMsg))
{
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
}
return((int)lpMsg.wParam);
}
LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
TCHAR str1[512], str2[512];
dados* dadosPartilhados;
dadosPartilhados = (dados*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch (messg)
{
case WM_CREATE:
EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_DISABLED | MF_GRAYED);
EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTOS, MF_DISABLED | MF_GRAYED);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_LOGIN:
DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LOGIN), hWnd, TrataEventosLogin);
EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_ENABLED);
EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTOS, MF_ENABLED);
break;
case ID_CONSULTA:
case ID_ACCELERATOR_CONSULTA:
LoadString(NULL, IDS_STR_CONSULTA, str1, 512);
_stprintf_s(str2, 512, TEXT("%s (%d)"), str1, dadosPartilhados->numOperacoes);
MessageBox(hWnd, str2, TEXT("String Table"), MB_OK | MB_ICONINFORMATION);
break;
case ID_ACCELERATOR_LEVANTAMENTOS:
case ID_LEVANTAMENTOS:
DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LEVANTAMENTO), NULL, TrataEventosLevantar);
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, messg, wParam, lParam);
break;
}
return(0);
}
LRESULT CALLBACK TrataEventosLogin(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
TCHAR username[16];
switch (messg)
{
case WM_COMMAND:
if (LOWORD(wParam) == IDOK)
{
GetDlgItemText(hWnd, IDC_EDIT_LOGIN, username, 16);
MessageBox(hWnd, username, TEXT("Username"), MB_OK | MB_ICONINFORMATION);
}
else if (LOWORD(wParam) == IDCANCEL)
{
EndDialog(hWnd, 0);
return TRUE;
}
break;
case WM_CLOSE:
EndDialog(hWnd, 0);
return TRUE;
}
return FALSE;
}
LRESULT CALLBACK TrataEventosLevantar(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
int i;
switch (messg)
{
case WM_INITDIALOG:
HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
SendMessage(hwndList, LB_RESETCONTENT, 0, 0);
for (i = 0; i < LIST_SIZE; i++)
SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)LIST_ITENS[i]);
break;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_LIST_MONTANTES)
{
switch (HIWORD(wParam))
{
case LBN_DBLCLK:
HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
i = (int)SendMessage(hwndList, LB_GETCURSEL, 0, 0);
MessageBox(hWnd, LIST_ITENS[i], TEXT("ListBox"), MB_OK | MB_ICONINFORMATION);
break;
}
}
break;
case WM_CLOSE:
EndDialog(hWnd, 0);
return TRUE;
}
return FALSE;
}
Alguns comentários:
#include <windows.h>
#include <Windowsx.h>
#include <tchar.h>
#include "resource.h" //aceder aos ids, macros simbólicas
#define NUM_CLIENTES 3
#define LIST_SIZE 8
TCHAR* LIST_ITENS[] = {
TEXT("10€"),
TEXT("20€"),
TEXT("40€"),
TEXT("60€"),
TEXT("80€"),
TEXT("100€"),
TEXT("150€"),
TEXT("200€")
};
//tratamento de eventos das janelas
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLogin(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLevantar(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosAcerca(HWND, UINT, WPARAM, LPARAM);
TCHAR szProgName[] = TEXT("Ficha8");
typedef struct {
unsigned int ID;
TCHAR username[16];
TCHAR password[16];
unsigned int saldo;
} cliente;
typedef struct {
unsigned int tipo; // 1 = depósito, 2 = levantamento
unsigned int quantia;
unsigned int ID;
} operacao;
//partilhar informação entre o mains e as funções de tratamentos de eventos
typedef struct {
cliente clientes[NUM_CLIENTES];
operacao historico[200];
unsigned int numOperacoes;
} dados;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
HWND hWnd;
MSG lpMsg;
WNDCLASSEX wcApp;
HANDLE hAccel;
dados dadosPartilhados; //partilha de recursos
wcApp.cbSize = sizeof(WNDCLASSEX);
wcApp.hInstance = hInst;
wcApp.lpszClassName = szProgName;
wcApp.lpfnWndProc = TrataEventos;
wcApp.style = CS_HREDRAW | CS_VREDRAW;
//para poder usar as macros fazer uso do MAKEINTRESOURCE
wcApp.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP));
wcApp.hIconSm = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP));
wcApp.hCursor = LoadCursor(hInst, MAKEINTRESOURCE(IDC_POINTER));
wcApp.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_PRINCIPAL);
wcApp.cbClsExtra = sizeof(dados);
wcApp.cbWndExtra = 0;
wcApp.hbrBackground = CreateSolidBrush(RGB(220, 220, 220));
if (!RegisterClassEx(&wcApp))
return(0);
hWnd = CreateWindow(
szProgName,
TEXT("SO2 - Ficha 8"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
300,
150,
(HWND)HWND_DESKTOP,
(HMENU)NULL,
(HINSTANCE)hInst,
0);
//partilha de recursos
dadosPartilhados.numOperacoes = 5; // Apenas para testar...
LONG_PTR x = SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)&dadosPartilhados);
ShowWindow(hWnd, nCmdShow);
//ciclo de processamentos das mensagens, dos atalhos
hAccel = LoadAccelerators(NULL, MAKEINTRESOURCE(IDR_ACCELERATOR));
while (GetMessage(&lpMsg, NULL, 0, 0))
{
if (!TranslateAccelerator(hWnd, hAccel, &lpMsg))
{
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
}
return((int)lpMsg.wParam);
}
LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
TCHAR str1[512], str2[512];
dados* dadosPartilhados;
dadosPartilhados = (dados*)GetWindowLongPtr(hWnd, GWLP_USERDATA); //partilha de recursos
switch (messg)
{
case WM_CREATE:
//código de inicialização do sistema
EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_DISABLED | MF_GRAYED);
EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTOS, MF_DISABLED | MF_GRAYED);
break;
case WM_COMMAND:
//a parte menos significativa trás o ID da opção da janela que deu origem ao WM_COMMAND
switch (LOWORD(wParam))
{
case ID_LOGIN:
//contexto, ID da macro da dialog box, o handler da janela principal, função para tratar o evento
DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LOGIN), hWnd, TrataEventosLogin);
EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_ENABLED);
EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTOS, MF_ENABLED);
break;
//a parte menos significativa trás o ID da opção da janela que deu origem ao WM_COMMAND
case ID_CONSULTA:
case ID_ACCELERATOR_CONSULTA:
LoadString(NULL, IDS_STR_CONSULTA, str1, 512);
_stprintf_s(str2, 512, TEXT("%s (%d)"), str1, dadosPartilhados->numOperacoes);
MessageBox(hWnd, str2, TEXT("String Table"), MB_OK | MB_ICONINFORMATION);
break;
case ID_ACCELERATOR_LEVANTAMENTOS:
case ID_LEVANTAMENTOS:
DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LEVANTAMENTO), NULL, TrataEventosLevantar);
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, messg, wParam, lParam);
break;
}
return(0);
}
LRESULT CALLBACK TrataEventosLogin(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
TCHAR username[16];
switch (messg)
{
case WM_COMMAND:
if (LOWORD(wParam) == IDOK)
{
GetDlgItemText(hWnd, IDC_EDIT_LOGIN, username, 16);
MessageBox(hWnd, username, TEXT("Username"), MB_OK | MB_ICONINFORMATION);
}
else if (LOWORD(wParam) == IDCANCEL)
{
EndDialog(hWnd, 0);
return TRUE;
}
break;
case WM_CLOSE:
EndDialog(hWnd, 0);
return TRUE;
}
return FALSE;
}
LRESULT CALLBACK TrataEventosLevantar(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
int i;
switch (messg)
{
case WM_INITDIALOG:
HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
SendMessage(hwndList, LB_RESETCONTENT, 0, 0);
for (i = 0; i < LIST_SIZE; i++)
SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)LIST_ITENS[i]);
break;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_LIST_MONTANTES)
{
switch (HIWORD(wParam))
{
case LBN_DBLCLK:
HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
i = (int)SendMessage(hwndList, LB_GETCURSEL, 0, 0);
MessageBox(hWnd, LIST_ITENS[i], TEXT("ListBox"), MB_OK | MB_ICONINFORMATION);
break;
}
}
break;
case WM_CLOSE:
EndDialog(hWnd, 0);
return TRUE;
}
return FALSE;
}
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);
}
sessão 10 – Programação gráfica orientada a eventos (os recursos win32)
O uso de recursos vem ajudar a construir elementos gráficos e sem ter que os desenhar!
Para fazer uso, é adicionar a um projeto vazio o recurso:

Existem vários tipos:
Sendo que uma das primeiras opções podem ser o Icon:
O ícone pode ser desenhado, pelo que é recomendado que primeiro se eliminem os que já existem, quando faltar um, adicionamos um vazio de 24 bits para termos o máximo de cores disponíveis, e de seguida voltamos a eliminar o ultimo ícone que ficou e que existia por defeito.
Usando a barra de desenho no topo podemos alterar este ícone
Nas propriedades podemos alterar o nome do ID, por exemplo para IDI_ICON_APP
Outro recurso pode ser o uso de menus..
Nas propriedades podemos indicar que as opções na barra de menus sejam de ação ao invés de mostrar outras opções no menu:
Popup -> FALSE
E as opções das caixas de diálogo:
Static Text
Edit Control
Button
Accelerator (para lidar com as teclas de atalho)
String Table
(…)

Nos Accelerator são definidas os comportamentos das teclas de atalho:

As Strings table (definir ID e definir um texto para eles):

e ainda o cursor, sendo que no final:

e os comportamentos dos componentes..
#include <windows.h>
#include <Windowsx.h>
#include <tchar.h>
#include "resource.h" //importante para acesso aos IDs..
#define NUM_CLIENTES 3
#define LIST_SIZE 8
TCHAR* LIST_ITENS[] = {
TEXT("10€"),
TEXT("20€"),
TEXT("40€"),
TEXT("60€"),
TEXT("80€"),
TEXT("100€"),
TEXT("150€"),
TEXT("200€")
};
//três soluções para tratamentos de eventos de janelas: dialog boxes
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLogin(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK TrataEventosLevantar(HWND, UINT, WPARAM, LPARAM);
TCHAR szProgName[] = TEXT("Ficha8");
typedef struct {
unsigned int ID;
TCHAR username[16];
TCHAR password[16];
unsigned int saldo;
} cliente;
typedef struct {
unsigned int tipo; // 1 = depósito, 2 = levantamento
unsigned int quantia;
unsigned int ID;
} operacao;
//estrutura agreagadora para nao usar variaveis globais
typedef struct {
cliente clientes[NUM_CLIENTES];
operacao historico[200];
unsigned int numOperacoes;
} dados;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
HWND hWnd;
MSG lpMsg;
WNDCLASSEX wcApp;
HANDLE hAccel;
dados dadosPartilhados;
wcApp.cbSize = sizeof(WNDCLASSEX);
wcApp.hInstance = hInst;
wcApp.lpszClassName = szProgName;
wcApp.lpfnWndProc = TrataEventos;
wcApp.style = CS_HREDRAW | CS_VREDRAW;
wcApp.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP)); // ID
wcApp.hIconSm = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_APP));
wcApp.hCursor = LoadCursor(hInst, MAKEINTRESOURCE(IDC_POINTER));
wcApp.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_PRINCIPAL);
wcApp.cbClsExtra = sizeof(dados); //janela tem espaço extra
wcApp.cbWndExtra = 0;
wcApp.hbrBackground = CreateSolidBrush(RGB(220, 220, 220));
if (!RegisterClassEx(&wcApp))
return(0);
hWnd = CreateWindow(
szProgName,
TEXT("SO2 - win 32"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
300,
150,
(HWND)HWND_DESKTOP,
(HMENU)NULL,
(HINSTANCE)hInst,
0);
dadosPartilhados.numOperacoes = 5; // Apenas para testar...
LONG_PTR x = SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)&dadosPartilhados); //obter da janela bytes da struct de dados
ShowWindow(hWnd, nCmdShow);
//processamento dos atalhos
hAccel = LoadAccelerators(NULL, MAKEINTRESOURCE(IDR_ACCELERATOR));
while (GetMessage(&lpMsg, NULL, 0, 0))
{
if (!TranslateAccelerator(hWnd, hAccel, &lpMsg))
{
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
}
return((int)lpMsg.wParam);
}
LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
TCHAR str1[512], str2[512];
dados* dadosPartilhados;
dadosPartilhados = (dados*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch (messg)
{
case WM_CREATE:
EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_DISABLED | MF_GRAYED);
EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTO, MF_DISABLED | MF_GRAYED);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_LOGIN:
DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LOGIN), hWnd, TrataEventosLogin);
EnableMenuItem(GetMenu(hWnd), ID_CONSULTA, MF_ENABLED); //ficam disponiveis
EnableMenuItem(GetMenu(hWnd), ID_LEVANTAMENTO, MF_ENABLED); //ficam disponiveis
break;
case ID_CONSULTA:
case ID_ACCELERATOR_C:
LoadString(NULL, IDS_STR_CONSULTA, str1, 512);
_stprintf_s(str2, 512, TEXT("%s (%d)"), str1, dadosPartilhados->numOperacoes);
MessageBox(hWnd, str2, TEXT("String Table"), MB_OK | MB_ICONINFORMATION);
break;
case ID_ACCELERATOR_L:
case ID_LEVANTAMENTO:
DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG_LEVANTAMENTO), NULL, TrataEventosLevantar);
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, messg, wParam, lParam);
break;
}
return(0);
}
LRESULT CALLBACK TrataEventosLogin(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
TCHAR username[16];
switch (messg)
{
//lidar com clique no menu
case WM_COMMAND:
if (LOWORD(wParam) == IDOK)
{
GetDlgItemText(hWnd, IDC_LEVANTAMENTO_LOGIN, username, 16);
MessageBox(hWnd, username, TEXT("Username"), MB_OK | MB_ICONINFORMATION);
}
else if (LOWORD(wParam) == IDCANCEL)
{
EndDialog(hWnd, 0);
return TRUE;
}
break;
case WM_CLOSE:
EndDialog(hWnd, 0);
return TRUE;
}
return FALSE;
}
LRESULT CALLBACK TrataEventosLevantar(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
{
int i;
switch (messg)
{
case WM_INITDIALOG:
HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
SendMessage(hwndList, LB_RESETCONTENT, 0, 0);
for (i = 0; i < LIST_SIZE; i++)
SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)LIST_ITENS[i]);
break;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_LIST_MONTANTES)
{
switch (HIWORD(wParam))
{
case LBN_DBLCLK:
HWND hwndList = GetDlgItem(hWnd, IDC_LIST_MONTANTES);
i = (int)SendMessage(hwndList, LB_GETCURSEL, 0, 0);
MessageBox(hWnd, LIST_ITENS[i], TEXT("ListBox"), MB_OK | MB_ICONINFORMATION);
break;
}
}
break;
case WM_CLOSE:
EndDialog(hWnd, 0);
return TRUE;
}
return FALSE;
}
sessão 10 – Programação gráfica orientada a eventos
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
Como começar?
no visualstudio 2019, podemos começar com uma aplicação normal de consola.
alterar de projeto gráfico nas propriedades
um exemplo de um ficheiro base:
nclude <windows.h>
#include <tchar.h>
/* ===================================================== */
/* Programa base (esqueleto) para aplicações Windows */
/* ===================================================== */
// Cria uma janela de nome "Janela Principal" e pinta fundo de branco
// Modelo para programas Windows:
// Composto por 2 funções:
// WinMain() = Ponto de entrada dos programas windows
// 1) Define, cria e mostra a janela
// 2) Loop de recepção de mensagens provenientes do Windows
// TrataEventos()= Processamentos da janela (pode ter outro nome)
// 1) É chamada pelo Windows (callback)
// 2) Executa código em função da mensagem recebida
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
// Nome da classe da janela (para programas de uma só janela, normalmente este nome é
// igual ao do próprio programa) "szprogName" é usado mais abaixo na definição das
// propriedades do objecto janela
TCHAR szProgName[] = TEXT("Base");
// ============================================================================
// FUNÇÃO DE INÍCIO DO PROGRAMA: WinMain()
// ============================================================================
// Em Windows, o programa começa sempre a sua execução na função WinMain()que desempenha
// o papel da função main() do C em modo consola WINAPI indica o "tipo da função" (WINAPI
// para todas as declaradas nos headers do Windows e CALLBACK para as funções de
// processamento da janela)
// Parâmetros:
// hInst: Gerado pelo Windows, é o handle (número) da instância deste programa
// hPrevInst: Gerado pelo Windows, é sempre NULL para o NT (era usado no Windows 3.1)
// lpCmdLine: Gerado pelo Windows, é um ponteiro para uma string terminada por 0
// destinada a conter parâmetros para o programa
// nCmdShow: Parâmetro que especifica o modo de exibição da janela (usado em
// ShowWindow()
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 é uma estrutura cujos membros servem para
// definir as características da classe da janela
// ============================================================================
// 1. Definição das características da janela "wcApp"
// (Valores dos elementos da estrutura "wcApp" do tipo WNDCLASSEX)
// ============================================================================
wcApp.cbSize = sizeof(WNDCLASSEX); // Tamanho da estrutura WNDCLASSEX
wcApp.hInstance = hInst; // Instância da janela actualmente exibida
// ("hInst" é parâmetro de WinMain e vem
// inicializada daí)
wcApp.lpszClassName = szProgName; // Nome da janela (neste caso = nome do programa)
wcApp.lpfnWndProc = TrataEventos; // Endereço da função de processamento da janela
// ("TrataEventos" foi declarada no início e
// encontra-se mais abaixo)
wcApp.style = CS_HREDRAW | CS_VREDRAW; // Estilo da janela: Fazer o redraw se for
// modificada horizontal ou verticalmente
wcApp.hIcon = LoadIcon(NULL, IDI_APPLICATION); // "hIcon" = handler do ícon normal
// "NULL" = Icon definido no Windows
// "IDI_AP..." Ícone "aplicação"
wcApp.hIconSm = LoadIcon(NULL, IDI_INFORMATION); // "hIconSm" = handler do ícon pequeno
// "NULL" = Icon definido no Windows
// "IDI_INF..." Ícon de informação
wcApp.hCursor = LoadCursor(NULL, IDC_ARROW); // "hCursor" = handler do cursor (rato)
// "NULL" = Forma definida no Windows
// "IDC_ARROW" Aspecto "seta"
wcApp.lpszMenuName = NULL; // Classe do menu que a janela pode ter
// (NULL = não tem menu)
wcApp.cbClsExtra = 0; // Livre, para uso particular
wcApp.cbWndExtra = 0; // Livre, para uso particular
wcApp.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
// "hbrBackground" = handler para "brush" de pintura do fundo da janela. Devolvido por
// "GetStockObject".Neste caso o fundo será branco
// ============================================================================
// 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("Exemplo de Janela Principal em C"),// Texto que figura na barra do título
WS_OVERLAPPEDWINDOW, // Estilo da janela (WS_OVERLAPPED= normal)
CW_USEDEFAULT, // Posição x pixels (default=à direita da última)
CW_USEDEFAULT, // Posição y pixels (default=abaixo da última)
CW_USEDEFAULT, // Largura da janela (em pixels)
CW_USEDEFAULT, // Altura da janela (em pixels)
(HWND) HWND_DESKTOP, // handle da janela pai (se se criar uma a partir de
// outra) 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, // handle da instância do programa actual ("hInst" é
// passado num dos parâmetros de WinMain()
0); // Não há parâmetros adicionais para a janela
// ============================================================================
// 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
// ============================================================================
// O Windows envia mensagens às janelas (programas). Estas mensagens ficam numa fila de
// espera até que GetMessage(...) possa ler "a mensagem seguinte"
// Parâmetros de "getMessage":
// 1)"&lpMsg"=Endereço de uma estrutura do tipo MSG ("MSG lpMsg" ja foi declarada no
// início de WinMain()):
// HWND hwnd handler da janela a que se destina a mensagem
// UINT message Identificador da mensagem
// WPARAM wParam Parâmetro, p.e. código da tecla premida
// LPARAM lParam Parâmetro, p.e. se ALT também estava premida
// DWORD time Hora a que a mensagem foi enviada pelo Windows
// POINT pt Localização do mouse (x, y)
// 2)handle da window para a qual se pretendem receber mensagens (=NULL se se pretendem
// receber as mensagens para todas as
// janelas pertencentes à thread actual)
// 3)Código limite inferior das mensagens que se pretendem receber
// 4)Código limite superior das mensagens que se pretendem receber
// NOTA: GetMessage() devolve 0 quando for recebida a mensagem de fecho da janela,
// terminando então o loop de recepção de mensagens, e o programa
while (GetMessage(&lpMsg,NULL,0,0)) {
TranslateMessage(&lpMsg); // Pré-processamento da mensagem (p.e. obter código
// ASCII da tecla premida)
DispatchMessage(&lpMsg); // Enviar a mensagem traduzida de volta ao Windows, que
// aguarda até que a possa reenviar à função de
// tratamento da janela, CALLBACK TrataEventos (abaixo)
}
// ============================================================================
// 6. Fim do programa
// ============================================================================
return((int)lpMsg.wParam); // Retorna sempre o parâmetro wParam da estrutura lpMsg
}
// ============================================================================
// FUNÇÃO DE PROCESSAMENTO DA JANELA
// Esta função pode ter um nome qualquer: Apenas é necesário que na inicialização da
// estrutura "wcApp", feita no início de // WinMain(), se identifique essa função. Neste
// caso "wcApp.lpfnWndProc = WndProc"
//
// WndProc recebe as mensagens enviadas pelo Windows (depois de lidas e pré-processadas
// no loop "while" da função WinMain()
// Parâmetros:
// hWnd O handler da janela, obtido no CreateWindow()
// messg Ponteiro para a estrutura mensagem (ver estrutura em 5. Loop...
// wParam O parâmetro wParam da estrutura messg (a mensagem)
// lParam O parâmetro lParam desta mesma estrutura
//
// NOTA:Estes parâmetros estão aqui acessíveis o que simplifica o acesso aos seus valores
//
// A função EndProc é sempre do tipo "switch..." com "cases" que descriminam a mensagem
// recebida e a tratar.
// Estas mensagens são identificadas por constantes (p.e.
// WM_DESTROY, WM_CHAR, WM_KEYDOWN, WM_PAINT...) definidas em windows.h
// ============================================================================
LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
switch (messg) {
case WM_DESTROY: // Destruir a janela e terminar o programa
// "PostQuitMessage(Exit Status)"
PostQuitMessage(0);
break;
default:
// Neste exemplo, para qualquer outra mensagem (p.e. "minimizar","maximizar","restaurar")
// não é efectuado nenhum processamento, apenas se segue o "default" do Windows
return(DefWindowProc(hWnd,messg,wParam,lParam));
break; // break tecnicamente desnecessário por causa do return
}
return(0);
}
uma unica janela e com a informação persistente..
#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
TCHAR szProgName[] = TEXT("Base");
//main
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
MSG lpMsg;
WNDCLASSEX wcApp;
//caracteristicas especificas de todas as janelas, comuns:
// o ícone, título, cor de fundo, localização
wcApp.cbSize = sizeof(WNDCLASSEX);
wcApp.hInstance = hInst;
wcApp.lpszClassName = szProgName;
wcApp.lpfnWndProc = TrataEventos;
wcApp.style = CS_HREDRAW | CS_VREDRAW;
wcApp.hIcon = LoadIcon(NULL, IDI_WARNING);
wcApp.hIconSm = LoadIcon(NULL, IDI_SHIELD);
wcApp.hCursor = LoadCursor(NULL, IDC_ARROW );
wcApp.lpszMenuName = NULL;
wcApp.cbClsExtra = 0;
wcApp.cbWndExtra = 0;
//wcApp.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));
if (!RegisterClassEx(&wcApp))
return(0);
//caracteristicas especificas de cada Janela!!! -> CreateWindow
hWnd = CreateWindow(
szProgName,
TEXT("S02 - Exercício 01"),
WS_OVERLAPPEDWINDOW,
200, // Posição x pixels
200, // Posição y pixels
600, // Largura da janela (em pixels)
600, // Altura da janela (em pixels)
(HWND)HWND_DESKTOP,
(HMENU)NULL,
(HINSTANCE)hInst,
0);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//ciclo que mantem o programa a funcionar
while (GetMessage(&lpMsg, NULL,0, 0)) {
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
return((int)lpMsg.wParam);
}
//função que trata os eventos, chamada pelo sistema operativo
//esta função pode estar associada a diferentes janelas
//coleção de eventos: UINT messg
//TCHAR c = '?'; //global
//para guardar o historial dos desenhos
typedef struct
{
int xPos;
int yPos;
TCHAR c;
} PosChar;
LRESULT CALLBACK TrataEventos(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) {
HDC hdc;
RECT rect;
//int xPos, yPos;
//static int xPos, yPos; //serem globais ou static para serem presistentes
static PosChar posicoes[500]; //array de posições
static int totalPos = 0;
int i;
static TCHAR chardAtual = '?'; //ou local
PAINTSTRUCT ps;
switch (messg) {
//evento que é sempre disparado qd acontece o refresh!
//todas as operações que escrevem na janela têm que surgir aqui WM_PAINT
//todas as operaçõe de escrita é aqui WM_PAINT
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps); //inicio de escrita na janela
//deseho
//hdc = GetDC(hWnd);
GetClientRect(hWnd, &rect); //toda a area do cliente
FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0))); //fundo da janela
SetTextColor(hdc, RGB(255, 0, 255));
SetBkMode(hdc, TRANSPARENT);
for (i = 0; i < totalPos; i++) {
rect.left = posicoes[i].xPos;
rect.top = posicoes[i].yPos;
DrawText(hdc, &posicoes[i].c, 1, &rect, DT_SINGLELINE | DT_NOCLIP);
}
//ReleaseDC(hWnd, hdc);
EndPaint(hWnd, &ps); //fim de escrita na janela
break;
//ignorar a limpeza do fundo, depois é usado o FillRect no WM_PAINT
case WM_ERASEBKGND:
return TRUE;
/*case WM_PAINT:
for(auto i : ops)
{
hdc = GetDC(hWnd);
GetClientRect(hWnd, &rect);
rect.bottom = i.xPos;
rect.top = i.yPos;
SetTextColor(hdc, RGB(0, 0, 0));
SetBkMode(hdc, TRANSPARENT);
DrawText(hdc, &i.pChar, 1, &rect, DT_SINGLELINE | DT_NOCLIP);
ReleaseDC(hWnd, hdc);
}
break;
*/
case WM_LBUTTONDOWN:
//xPos = GET_X_LPARAM(lParam); //#include <windowsx.h>
//yPos = GET_Y_LPARAM(lParam); //#include <windowsx.h>
if(totalPos<500){
posicoes[totalPos].xPos = GET_X_LPARAM(lParam); //#include <windowsx.h>
posicoes[totalPos].yPos = GET_Y_LPARAM(lParam); //#include <windowsx.h>
posicoes[totalPos].c = chardAtual;
totalPos++;
InvalidateRect(hWnd, NULL, FALSE); //refresh da janela, ajuda a lidar com o fundo
}
////deseho
//hdc = GetDC(hWnd);
//GetClientRect(hWnd, &rect);
//SetTextColor(hdc, RGB(255, 0, 255));
//SetBkMode(hdc, TRANSPARENT);
//rect.left = xPos;
//rect.top = yPos;
//DrawText(hdc, &c, 1, &rect, DT_SINGLELINE | DT_NOCLIP);
//ReleaseDC(hWnd, hdc);
break;
case WM_CHAR:
chardAtual = (TCHAR)wParam;
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);
}
lidar com animações e com o flickering / oscilante
#include <windows.h>
#include <tchar.h>
#include <windowsx.h>
LRESULT CALLBACK TrataEventos(HWND, UINT, WPARAM, LPARAM);
TCHAR szProgName[] = TEXT("Base");
//(todas elas vão ser inicializadas na main, e não podem ser usadas variaveis estáticas)
//mas podia estar dentro de uma estrutura
//handle/acesso para o bitmap
HBITMAP hBmp;
//handle para o device content, o que vai permitir passar o bmp para este formato
HDC bmpDC;
//informação sobre a estrutura do bitmap (pe: largura e altura..)
BITMAP bmp;
//posição da imagem
int xBitmap;
int yBitmap;
//ou isto assim agora ou criar uma estrutura!
int limDireitoJanela;
HWND hWandGlobal;
//lidar com o flikring a centilação e lidar com os acesso concorrentes: mutex
HANDLE hMutex;
//lidar com a copia em memoria, double buffering
HDC memoriaCopiaDC = NULL;
HBITMAP hCopiaBitMap;//vai copiar as caracteristicas para a copia
//crair uma thread para lidar com as animações/tempo que passa
DWORD WINAPI movimentaImagem(LPVOID param)
{
int direcaoMovimento = 1; //1, direita e -1, esquerda
int salto = 2; //salto de posições em termos de pixeis
while(1)
{
WaitForSingleObject(hMutex, INFINITE);
xBitmap = xBitmap + (direcaoMovimento * salto);
if(xBitmap <=0)
{
xBitmap = 0;
direcaoMovimento = 1;
}
else if(xBitmap >= limDireitoJanela)
{
xBitmap = limDireitoJanela;
direcaoMovimento = -1;
}
ReleaseMutex(hMutex);
//temos sempre que avisar o sistema para fazer uma nova pintura da janela
InvalidateRect(hWandGlobal, NULL, FALSE);
Sleep(1);
}
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
MSG lpMsg;
WNDCLASSEX wcApp;
//caracteristicas especificas de todas as janelas, comuns:
// o ícone, título, cor de fundo, localização
wcApp.cbSize = sizeof(WNDCLASSEX);
wcApp.hInstance = hInst;
wcApp.lpszClassName = szProgName;
wcApp.lpfnWndProc = TrataEventos;
wcApp.style = CS_HREDRAW | CS_VREDRAW;
wcApp.hIcon = LoadIcon(NULL, IDI_WARNING);
wcApp.hIconSm = LoadIcon(NULL, IDI_SHIELD);
wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);
wcApp.lpszMenuName = NULL;
wcApp.cbClsExtra = 0;
wcApp.cbWndExtra = 0;
//wcApp.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wcApp.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));
if (!RegisterClassEx(&wcApp))
return(0);
//caracteristicas especificas de cada Janela!!! -> CreateWindow
hWnd = CreateWindow(
szProgName,
TEXT("S02 - Exercício 01"),
WS_OVERLAPPEDWINDOW,
200, // Posição x pixels
200, // Posição y pixels
600, // Largura da janela (em pixels)
600, // Altura da janela (em pixels)
(HWND)HWND_DESKTOP,
(HMENU)NULL,
(HINSTANCE)hInst,
0);
//aqui vem a a informação do bitmap
//1º carregar o bitmap (124x124)
hBmp = LoadImage(NULL, TEXT("flag.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
//ir buscar informações sobre o recurso, carregar os metadados da imagem
GetObject(hBmp, sizeof(bmp), &bmp);
//passar do handle da imagem para o device content
HDC hdc;
hdc = GetDC(hWnd);
//criar uma copia
bmpDC = CreateCompatibleDC(hdc); //devolve um novo handle
//aplicar o bitmap ao device content
SelectObject(bmpDC, hBmp);
//fechar o device content da janela
ReleaseDC(hWnd, hdc);
//definir as posições iniciais da imagem, e centrar por exemplo
RECT rect;
GetClientRect(hWnd, &rect);
//xBitmap = (LARGURA_JANELA / 2) - (bmp.bmWidth/2);
//yBitmap = (ALTURA_JANELA / 2) - (bmp.bmHeight / 2);
xBitmap = (rect.right / 2) - (bmp.bmWidth/2);
yBitmap = (rect.bottom / 2) - (bmp.bmHeight / 2);
//escrever a imagem no tratamento de eventos..
//definir o que é o limite dieito
limDireitoJanela = rect.right - bmp.bmWidth;
hWandGlobal = hWnd;
hMutex = CreateMutex(NULL, FALSE, NULL);
//criar a thread
CreateThread(NULL, 0, movimentaImagem, NULL, 0, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//ciclo que mantem o programa a funcionar
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); //inicio de escrita na janela
GetClientRect(hWnd, &rect); //toda a area do cliente
//fazer a copia para o buffering
if(memoriaCopiaDC == NULL)
{
//ainda nao foi feita a copia em memoria
//criar a copia
memoriaCopiaDC = CreateCompatibleDC(hdc);
//obter as caracteristicas, copia figdigna mas falta lidar com o resize..
hCopiaBitMap = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
SelectObject(memoriaCopiaDC, hCopiaBitMap);
DeleteObject(hCopiaBitMap); //libertar recursos
}
//FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 255, 0))); //fundo da janela
FillRect(memoriaCopiaDC, &rect, CreateSolidBrush(RGB(0, 255, 0))); //fundo da janela
WaitForSingleObject(hMutex, INFINITE);
//BitBlt(hdc, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
BitBlt(memoriaCopiaDC, xBitmap, yBitmap, bmp.bmWidth, bmp.bmHeight, bmpDC, 0, 0, SRCCOPY);
//SRCCOPY copiar a totalidade dos pixeis
ReleaseMutex(hMutex); // resolver problemas do xBitmap, yBitmap
//vai ser necessário copiar para a principal
BitBlt(hdc,0,0, rect.right, rect.bottom, memoriaCopiaDC, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
break;
//lidar com o resize da janela, redimensionamento da janela
case WM_SIZE:
WaitForSingleObject(hMutex, INFINITE);
//LOWORD(lParam) -> menos significativa representa a largura
//HIWORD(lParam) -> mais significativa representa a altura
xBitmap = (LOWORD(lParam) / 2) - (bmp.bmWidth / 2);
yBitmap = (HIWORD(lParam) / 2) - (bmp.bmHeight / 2);
//temos tb que ajusatr o limite da janela
limDireitoJanela = LOWORD(lParam) - bmp.bmWidth;
//libterar o memoriaCopiaDC
ReleaseDC(hWnd, memoriaCopiaDC);
memoriaCopiaDC = NULL;
ReleaseMutex(hMutex);
break;
case WM_ERASEBKGND:
return TRUE;
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);
}


































