Desenhar o conteudo da janela
Parte 2: Objectos
Mais uma vez vais copiar/colar este código para a parte do código onde diz /* Parte 2 do Tut */“ mesmo por cima da função WindowProcedure
Código:
#define ID_BUTTONmais 1001
#define ID_BUTTONmenos 1002
#define ID_BUTTONvezes 1003
#define ID_BUTTONdividir 1004
HINSTANCE g_inst;
HWND EditNum1,EditNum2,EditTotal,ButtonMais,ButtonMenos,ButtonVezes,ButtonDividir;
//esta função só serve para criar o conteudo dentro da janela principal (nao tem retorno)
//irá criar duas EDITs e 4 BUTTONS, e mudar os respectivos tipos de letra de cada um
void DesenharObjectos(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
EditNum1 = CreateWindowEx (
WS_EX_CLIENTEDGE,
"EDIT",
"5",
WS_VISIBLE|WS_CHILD|WS_BORDER,
30, 30, 50, 20,
hwnd,
NULL,
g_inst,
NULL
);
EditNum2 = CreateWindowEx (
WS_EX_CLIENTEDGE,"EDIT", "3",
WS_VISIBLE|WS_CHILD|WS_BORDER,
160, 30, 50, 20,
hwnd, NULL, g_inst, NULL );
EditTotal = CreateWindowEx (
WS_EX_CLIENTEDGE,"EDIT", "",
WS_VISIBLE|WS_CHILD|WS_BORDER,
220, 30, 50, 20,
hwnd, NULL, g_inst, NULL );
ButtonMais = CreateWindowEx (
0,
"BUTTON",
"+",
WS_VISIBLE|WS_CHILD,
80, 30, 20, 20,
hwnd,
(HMENU)ID_BUTTONmais,
g_inst,
NULL
);
ButtonMenos = CreateWindowEx (
0, "BUTTON", "-",
WS_VISIBLE|WS_CHILD,
100, 30, 20, 20,
hwnd, (HMENU)ID_BUTTONmenos, g_inst, NULL);
ButtonVezes = CreateWindowEx (
0, "BUTTON", "*",
WS_VISIBLE|WS_CHILD,
120, 30, 20, 20,
hwnd, (HMENU)ID_BUTTONvezes, g_inst, NULL);
ButtonDividir = CreateWindowEx (
0, "BUTTON", "/",
WS_VISIBLE|WS_CHILD,
140, 30, 20, 20,
hwnd, (HMENU)ID_BUTTONdividir, g_inst, NULL);
CreateWindowEx (
0,
"STATIC",
"=",
WS_VISIBLE|WS_CHILD,
212, 31, 5, 20,
hwnd,
NULL,
g_inst,
NULL
);
SendMessage(
(HWND) EditNum1,
(UINT) WM_SETFONT,
(WPARAM) GetStockObject(DEFAULT_GUI_FONT),
(LPARAM) lParam
);
SendMessage((HWND) EditNum2,(UINT) WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT),(LPARAM) lParam);
SendMessage((HWND) EditTotal,(UINT) WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT),(LPARAM) lParam);
SendMessage(
(HWND) ButtonMais,
(UINT) WM_SETFONT,
(WPARAM) GetStockObject(DEFAULT_GUI_FONT),
(LPARAM) lParam
);
SendMessage((HWND) ButtonMenos,(UINT) WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT),(LPARAM) lParam);
SendMessage((HWND) ButtonVezes,(UINT) WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT),(LPARAM) lParam);
SendMessage((HWND) ButtonDividir,(UINT) WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT),(LPARAM) lParam);
}
Vais também tirar as duas barras "//" da função "DesenharObjectos(hwnd,message,wParam,lParam);" na função WindowProcedure dentro do “case WM_CREATE:” para que ela possa ser executada.
(F9 pra ver se está tudo em ordem. tks)
É tudo.
Ao executares o programa, reparas que a calculadora tem agora 4 botões, 3 edits e 1 label.
Vamos começar pelo princípio.
A janela principal foi criada pela função WinMain, esta executou a função WindowProcedure e enviou-nos a “message” de WM_CREATE que significa que a janela acabou de ser criada, tal como seria de esperar.
Tu com um
switch filtraste o momento de quando ela foi criada “
case WM_CREATE:” então vais aproveitar esse momento de criação para desenhar os botões, edits etc.
Como a parte de desenhar objectos é algo extensa onde 90% do código é repetido, eu decidi criar uma outra função para nao “sujar” a nossa função de trabalho que é a
WindowProcedure.
A técnica que usei foi criar uma função sem retorno (procedimento em pascal) a função vai-se chamar
DesenharObjectos() e é dentro dela que vais desenhar tudo, se reparas ela a função transporta as 4 variáveis que já expliquei na Parte 1 do Tut, ela faz esse transporte porque convem levares contigo as ferramentas se vais trabalhar para outro local..
Então a função “DesenharObjectos(hwnd,message,wParam,lParam);” apenas te transporta para outro lado ("lá pra cima" neste caso).
Vais então analizar o novo código com atenção.
Antes da função
DesenharObjectos() à sempre que declarar as variáveis, neste caso vou declarar os objectos com que vou trabalhar:
Aqui estão os nomes dos teus 3 edits e dos 4 butoes
“HWND EditNum1,EditNum2,EditTotal,ButtonMais,ButtonMenos,ButtonVezes,ButtonDividir;”
Vais passar agora para dentro da função
DesenharObjectos()
(sim eu sei, saltei a instrução “HINSTANCE g_inst;” de prepósito)
Código:
void DesenharObjectos(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
logo no principio da função tens isto
Código:
EditNum1 = CreateWindowEx (
WS_EX_CLIENTEDGE,
"EDIT",
"5",
WS_VISIBLE|WS_CHILD|WS_BORDER,
30, 30, 50, 20,
hwnd,
NULL,
g_inst,
NULL
);
Este pequeno código vai-te criar uma editbox, o processo de criação é igual para quase todos os objectos, já te mostro de perto.
Código:
EditNum1 = CreateWindowEx(
esta linha diz que EditNum1 vai ser igual a um objecto criado pela função
CreateWindowEx()
A função
CreateWindowEx para ser executada precisa sempre de 12 parametros que são os seguintes (por ordem).
CreateWindowEx(
1º - !Aparencia do objecto! neste caso é “WS_EX_CLIENTEDGE” que dá o efeito 3d ao edit, experimenta colocar um 0 em vez do “WS_EX_CLIENTEDGE” e corre o programa, ficou flat nao foi? (depois de modificares convem colocar como estava para tudo funcionar como pretendo)
2º - !Classe do objecto! Neste caso é “EDIT” porque queremos uma editbox, se quizessemos um botão teriamos que por “BUTTON", experimenta colocar “BUTTON” como 2 parametro. Éra de esperar, transformou-se num botão.
3º - !Texto default do Objecto! Neste caso o default é “5” experimenta por algo do tipo “rotfl”. Compile & Run
4º - !Aparencia especifica do objecto! Neste caso usa 3 constantes, WS_VISIBLE|WS_CHILD|WS_BORDER,
WS_VISIBLE faz com que o objecto seja visivel,
WS_BORDER faz que tenha uma borda/moldura neste caso 3d,
WS_CHILD informa que o objecto está dentro de uma janela. Todas estas constantes sao separadas por uma barra “|” para poder funcionar. Experimenta adicionar
ES_RIGHT e vais reparar que ele alinhou o texto à direita. Lembra-te que podes adicionar o que quiseres, 2, 5 ou 10 aparencias malucas, tem é de ter sempre a barra a separar!
5º - !Distancia da esquerda! esquerda ou direita, se tiveres habituado a programação por objectos, fazes isto com alguma facilidade.
6º - !Distancia do topo! Estas coordenadas são sempre em pixels, se alterares os valores vais fazer com que o edit se mova pra cima ou para baixo
7º - !Largura!
8º - !Altura!
9º - !Janela em que vai ser criado o objecto! Na Parte 1 do tutorial já te mostrei que hwnd era o ponteiro da nossa janela, como tu vais querer colocar o objecto dentro da tua janela mãe, só tens que indicar o apontador aqui “hwnd” (não há brincadeiras com este parametro =P)
10º - !Numero de identificação! Ora bem neste caso é Null, ou seja, não foi atribuido nenhum numero ID a esta edit, isto porque não é necessário. Fica assim.
11º - !instancia! lembras-te de eu saltar o “HINSTANCE g_inst;” na secção das variaveis? É aqui que devemos por o “g_inst” que é o manipulador da instancia associada à nossa janela (não percebeste? Eu tb nunca percebi mt bem lol...)
12º - !lparam! tb nao sei mas é sempre NULL.
);
É assim que se cria um objecto, agora segue um pouco mais o código com atenção.
Código:
EditNum2 = CreateWindowEx (
WS_EX_CLIENTEDGE,"EDIT", "3",
WS_VISIBLE|WS_CHILD|WS_BORDER,
160, 30, 50, 20,
hwnd, NULL, g_inst, NULL );
EditTotal = CreateWindowEx (
WS_EX_CLIENTEDGE,"EDIT", "",
WS_VISIBLE|WS_CHILD|WS_BORDER,
220, 30, 50, 20,
hwnd, NULL, g_inst, NULL );
Os objectos EditNum2 e EditTotal são editboxs iguaizinhas a esta que acabamos de criar, só muda o nome e as coordenadas onde vao ser desenhadas (porque senão ficavam todas umas em cima das outras, sim, tambem muda o texto default (3º parametro) que já me tava a esquecer..)
O aspecto diferente do código deve-se a eu ter compactado vários parametros na mesma linha (para não ocupar tanto) hàs-de reparar que estão lá todos os 12 parametros separados por virgulas ",".
Vais seguir again o código até encontrares “ButtonMais = CreateWindowEx (“
Código:
ButtonMais = CreateWindowEx (
0,
"BUTTON",
"+",
WS_VISIBLE|WS_CHILD,
80, 30, 20, 20,
hwnd,
(HMENU)ID_BUTTONmais,
g_inst,
NULL
);
As anteriores eram “EDIT”, estes agora são “BUTTON”, o processo de criação é igual, mas neste caso o botão não precisa de WS_BORDER no 4º parametro, nem "WS_EX_CLIENTEDGE" no 1º como as editboxs, MAS tem um Número de Identificação no 10º!
Vou-te explicar o que é o Número de Identificação (ID).
O ID é um número que se atribui a um objecto, a atribuição é feita da seguinte maneira “(HMENU) NumeroAqui” neste caso defeni que seria 1001. (se reparares eu no inicio do programa defeni que “ID_BUTTONmais” seria igual a “1001”;“#define ID_BUTTONmais 1001”)
Costuma-se usar “#define QualquerCoisa ID” porque é mais facil para programar com nomes do que com números. Este é um programa pequeno, sei que há 4 butoes com os IDs 1001 para o ButtonMaiso, 1002 para o ButtonMenos etc,etc, mas num programa grande convem sempre usar o #define para facilitar.
Código:
#define ID_BUTTONmais 1001
#define ID_BUTTONmenos 1002
#define ID_BUTTONvezes 1003
#define ID_BUTTONdividir 1004
O número ID é muito bonito mas para que serve? Perguntas tu...
Quando o botão ButtonMais é clicado o Windows envia-nos as informações
BN_CLICKED na variavel
HIWORD(wParam) e o ID na
LOWORD(wParam),
BN_CLICKED é quando o user clica num botão, e se ele enviar também 1001 é porque o ButtonMais foi clicado, 1002 foi o ButtonMenos, 1003 foi o ButtonVezes etc.
Resumindo: se ((HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == 1001)) é porque alguém clicou no botão de mais.
Se continuares a seguir o código, reparas que só mudam os nomes das variáveis, os IDs e o texto default (claro também mudam as coordenadas)
Segue então mais uma vez no código, e pára na “CreateWindowEx (“ que não foi compactada por mim). Esta diz "STATIC", no 2º parametro não é?
Código:
CreateWindowEx (
0,
"STATIC",
"=",
WS_VISIBLE|WS_CHILD,
212, 31, 5, 20,
hwnd,
NULL,
g_inst,
NULL
);
Sabes que “BUTTON” faz botões, sabes que “EDIT” faz editboxs, mas “STATIC” é novo!
“STATIC” é conhecido por Label, na tua calculadora esta label é o sinal de igual “=”, é um objecto que não serve para nada, apenas aparece para fazer sentido ao interface da tua calculadora. Como este “STATIC” não vai fazer nada, não temos que atribuir variável alguma, nem tanto um ID (é serve para o interface ficar bonito).
Toca a seguir mais no código.
Código:
SendMessage(
(HWND) EditNum1,
(UINT) WM_SETFONT,
(WPARAM) GetStockObject(DEFAULT_GUI_FONT),
(LPARAM) lParam
);
Antes de saber para que serve este pequeno código temos que ter a noção que:
o Windows comunica com o nosso programa básicamente atravez de mensagens, enviam-se mensagens, recebe-se mensagens, a função SendMessage() é composto por 4 parametros:
SendMessage(
1º - !Objecto destino! Este é o objecto a que é destinado a mensagem, no código a cima podemos ver que é o EditNum1
2º - !Mensagem enviada! Conforme a mensagem enviada, faz o objecto reagir de formas diferentes, no nosso caso a mensagem é
WM_SETFONT, ou seja
o objecto vai trocar o seu tipo de letra, e o novo tipo de letra será enviado atravez do 3º parametro (wParam)
3º - !wParam! Estamos no 3º parametro, e tu deves tar a perguntar “HEI como é que sabes que o tipo de letra tem de ir como 3º parametro e como sabes que
WM_SETFONT muda de letra??” é simples, MSDN mais própriamente aqui ->
http://msdn.microsoft.com/library/d...windowreference/windowmessages/wm_setfont.asp
Como já disse em Nota: não há programas sem consulta, deves conhecer bem os locais a consultar e ganhar hábito em consultas, só um doido é que sabe de cor como reage um objecto a cada mensagem diferente!
4º - !lParam! este parametro não serve para nada segundo diz o MSDN, por isso vamos reenviar o próprio lParam.
);
Pois é, esta SendMessage() faz mudar o tipo de letra da caixa de texto EditNum1, a nova letra que vais usar é o tipo de letra DEFAULT_GUI_FONT (tipo default do windows).
Sim, é preciso dizer ao Windows que o tipo de letra que queremos é o default do Windows, experimenta tirar o “(WPARAM) GetStockObject(DEFAULT_GUI_FONT),” e colocar “(WPARAM) 0,”, vês logo porque é que eu troquei de letra, pois o Windows por defeito usa FONTS HORRIVEIS!!!!!
A função
GetStockObject() é uma função muito simpática que existe, ela retorna as coisas mais usadas do Windows. Por exemplo
GetStockObject(DEFAULT_GUI_FONT) como já sabes, é a font default do windows
GetStockObject(GRAY_BRUSH) é cinzento.
GetStockObject(DEFAULT_PALETTE) é a palete default do windows
entre outras coisas.
Se existisse esta função
GetStockObject() terias que criar uma variável do tipo fontl, e atribuir-lhe uma fonte;
Código:
HFONT Minhaletra;
Minhaletra = CreateFont(
24,
0,
0,
0,
FW_BOLD,
FALSE,
FALSE,
FALSE,
ANSI_CHARSET,
OUT_CHARACTER_PRECIS,
CLIP_CHARACTER_PRECIS,
PROOF_QUALITY,
VARIABLE_PITCH | FF_DONTCARE,
"Comic Sans MS"
);
Por isso! Um bem haja ao
GetStockObject() que nos livra de tal trabalheira!
(podes consultar GetStockObject() no MSDN, alias o MSDN tem tudo! é preciso é saber procurar)
O resto do código até ao terminar da função
DesenharObjector() apenas muda os tipos de letras aos restantes objectos da nossa janela, não deves ter dificuldades em decifrar.
Parte 2: Terminada