3630 registros
0 hoje
14 nesta semana
4 neste mês|
Sex 28 Nov 2008 09:57 |
|
Página 1 de 2
A vontade de ver as coisas funcionarem depressinha é grande. Ficar digerindo teoria é o tipo da coisa chata. O melhor é ver o resultado e depois esmiuçar a teoria - aí a coisa não fica no ar. Então, já que estamos programando para Windows, que tal encarar uma janela de verdade? Criando o projetoOs passos para criar um projeto você já conhece: |Project|Create|, dar nome ao projeto (eu dei o nome de "janela"), selecionar o diretório de trabalho (continuei usando o /lcc/projects/teste/), selecionar "Windows application" e clicar em [Create]. Confirme o diretório com [Yes], aceite o wizard com [Yes]. Selecione "Single window" e clique em [Ok], [Next], [Finish] e novamente em [OK]. Deixe tudo como está e clique em [Next], [Next] e [Finish] para finalmente chegar na janela de edição. Deu para perceber que aceitamos todas as configurações apresentadas pelo wedit - só tivemos o trabalho de assinalar "Windows application". Dando uma olhada no código fonte gerado automaticamente, dá para perceber que é um pouco mais elaborado do que o código fonte da caixa de diálogo. Algumas coisas já conhecemos, em compensação tem umas outras que... bem, serão vistas mais para frente. Compile e rode o programa. O que se vê é uma janela de fundo branco, com uma barra de título na parte superior, uma barra de status na parte inferior e um menu - este é o esqueleto de um aplicativo windows (mas não esquecido dentro do armário Analisando o código fonteComo sempre, vamos começar com a função WinMain. Sabemos que ela não pode faltar, pois é a porta de entrada do nosso aplicativo: int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) { MSG msg; HANDLE hAccelTable; hInst = hInstance; if (!InitApplication()) return 0; hAccelTable = LoadAccelerators(hInst,MAKEINTRESOURCE(IDACCEL)); if ((hwndMain = CreatejanelaWndClassWnd()) == (HWND)0) return 0; CreateSBar(hwndMain,"Ready",1); ShowWindow(hwndMain,SW_SHOW); while (GetMessage(&msg,NULL,0,0)) { if (!TranslateAccelerator(msg.hwnd,hAccelTable,&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } O esquema básico é o mesmo dos nossos projetos de caixas de diálogo, mas esta função é mais parruda: iniciamos o aplicativo chamando a função InitApplication (onde será registrada a classe da janela, etc), carregamos os aceleradores de teclado (as teclas de atalho), criamos a janela, a barra de status, mostramos a janela na tela e entramos num loop de mensagens - o mesmo que dizer que entramos na central de comunicação do nosso programa. A única mensagem que pode nos "expulsar" da central de comunicação é a WM_QUIT. Como sempre, um aplicativo windows nada mais é do que receber e enviar mensagens entre o sistema operacional e a central de comunicação do nosso programa. Vamos analisar o código por partes, começando com a primeira função chamada, a InitApplication. A inicializaçãoEste procedimento começa manifestando a estrutura wc, do tipo WNDCLASS (esta estrutura já está manifestada no arquivo cabeçalho windows.h que inclui o win.h). Não é a primeira vez que falamos em estruturas, aliás, um conceito tão importante que será o assunto do próximo tutorial. Se quiser se antecipar, dê uma lida em Estruturas e Uniões e depois volte para este texto. Vamos dar uma olhada na função estática InitApplication, que não precisa de parâmetros (void) e que retorna um valor lógico ou BOOL (1=verdadeiro ou 0=falso): static BOOL InitApplication(void) { WNDCLASS wc; memset(&wc,0,sizeof(WNDCLASS)); wc.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS ; wc.lpfnWndProc = (WNDPROC)MainWndProc; wc.hInstance = hInst; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszClassName = "janelaWndClass"; wc.lpszMenuName = MAKEINTRESOURCE(IDMAINMENU); wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hIcon = LoadIcon(NULL,IDI_APPLICATION); if (!RegisterClass(&wc)) return 0; return 1; } O estilo da janela (wc.style) é uma combinação de constantes inteiras (CS_HREDRAW, CS_VREDRAW e CS_DBLCLKS) feita através do operador OR, representado por uma barra vertical. O operador OR, um operador lógico cuja tradução é OU, é o modo padrão da linguagem C manipular bits. Quais bits? Neste caso, dos valores correspondentes às constantes. Experimente o seguinte: clique com o botão direito do mouse sobre CS_HREDRAW e escolha |Show definition of CS_HREDRAW|. Na janelinha pop-up é possível verificar que o valor desta constante é 2. Faça o mesmo com as outras duas. A declaração wc.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS; pode ser traduzida para wc.style = 2 OR 1 OR 8; ou wc.style = 2 | 1 | 8;. Aliás, HREDRAW pode ser traduzido para "Redesenhar a Horizontal", VREDRAW para "Redesenhar a Vertical" e DBLCLKS para "Cliques Duplos". Note que os valores das constantes são potências de 2, ou seja, 2 é igual a 2 elevado a 1, 1 é igual a 2 elevado a 0 e 8 é igual a 2 elevado a 3. Existe uma regrinha fácil de ser guardada: toda potência de 2 possui apenas um único bit com valor 1; todos os outros bits estão zerados. Outra dica: a operação lógica OR é a comparação de dois bits. Apenas se os dois bits forem 0, o resultado será 0; caso contrário, será 1. Conhecendo os valores e sabendo como funciona o OR, fica fácil perceber que 2 OR 1 OR 8, expresso em binário, será 0010 OR 0001 OR 1000, o que é igual a 1011, que correspode a 11 na notação decimal. Na verdade, cada bit desta "tripinha" de 4 bits, onde os bits são numerados da direita para a esquerda a partir de 0, funciona como uma flag: bit 0 ligado = janela redesenha na vertical; bit 1 ligado = janela redesenha na vertical; bit 3 ligado = janela aceita duplos cliques. Logo após, ao invés de usar o DefDialogProc (próprio para caixas de diálogo), atribui-se o MainWndProc. O restante não difere da definição da estrutura WNDCLASS vista nas caixas de diálogo. A tabela de teclas de atalhoOs aceleradores, dispostos em uma tabela, são as de teclas de atalho que permitem o acesso rápido a itens de menu sem o uso do mouse. Encontram-se nos recursos e podem ser editados. Clique em |Design|New/Open|, a seguir escolha janelares.h, clique em [Open] e escolha "Accelerator" com um duplo clique. Você obterá uma janela de teclas aceleradoras indicando IDM_EXIT, com o valor 300 e com um valor de tecla ("Key value") de 81. 81 corresponde ao valor ASCII da letra "q". Dê um duplo clique na linha do "Key value" 81 para obter a janela "Changing an accelerator key". Você pode mudar, adicionar ou eliminar teclas aceleradoras. Fique à vontade... só que, como já compilamos nosso programa, as alterações nos recursos terão de ser feitas "na unha", o que é assunto para mais tarde. Isto foi só um adendo. Vamos voltar à vaca fria... A central de mensagensApós carregar os aceleradores, é criada a barra de status no rodapé da janela e, finalmente, a janela é mostrada. Até então, enquanto estava sendo "enfeitada", a janela permaneceu "escondida". Isto impediu que uma janela inacabada ficasse sassaricando na tela, mareando o usuário, e economizou muito tempo de execução. Na verdade, a parte mais importante é o loop de mensagens que vem logo depois da chamada à função da API ShowWindow (mostre a janela): ... ShowWindow(hwndMain,SW_SHOW); while (GetMessage(&msg,NULL,0,0)) { if (!TranslateAccelerator(msg.hwnd,hAccelTable,&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } ... Este loop, administrado por um comando de controle de fluxo while, chama a função da API GetMessage (pegar mensagem). Se a função retornar verdadeiro (TRUE), chamamos novamente a API para traduzir teclas aceleradoras (TranslateAccelerator). Esta função converterá uma sequência de teclas digitadas numa mensagem WM_COMMAND, como se tivesse sido enviada por um item de menu, se encontrar uma correspondência entre as teclas digitadas e a tabela de aceleradores que foi carregada algumas linhas antes. Se TranslateAccelerator não encontrar nenhuma correspondência, a linha de execução passa para a função da API TranslateMessage (traduzir mensagem). Esta função controla as teclas digitadas e realiza o trabalho penoso de depurar a digitação do usuário (controlar sequências repetidas, intervalos, etc). Finalmente é chamada a função da API DispatchMessage (despachar mensagem), que envia a mensagem para o procedimento indicado na classe janela, o MainWndProc. É isso aí. Ficamos dando voltas e mais voltas neste loop até que, num dado momento seja gerada a mensagem WM_QUIT (terminar). Esta mensagem faz com que GetMessage retorne FALSE, interrompendo o loop e terminando o programa. |
||||
| Última atualização ( Sex, 28.11.2008 11:09 ) |