A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Tutoriais e Programação

Linguagem C - Caçando informações

Qui

27

Nov

2008


14:02

(11 votos, média 4.00 de 5) 


Conferindo o resultado

Se você fez as alterações propostas até agora, teve a pachorra de salvar o arquivo, fazer a compilação e conseguiu rodar o programa, não notou diferença nenhuma. Simplesmente é preciso acreditar que o texto do campo ID_EDICAO foi transferido para o balaio - não tem como ver. Como isto é muito chato, vamos espiar a área de memória usando a função da API MessageBox que cria uma caixa de mensagem. É uma saída de preguiçoso porque, usando esta função, não será preciso registrar uma classe janela, definir mais um procedimento, etc e tal.

A MessageBox precisa como parâmetros o manipulador da janela-mãe (já deu para perceber que o sistemão adora handles), o buffer onde se encontra o texto que deve ser mostrado, uma string com o título da caixa de mensagem e o botão (ou botões) que acompanham a caixa. Aproveitando a interceptação do botão [OK], logo depois da função PegaTexto, entre o texto das linhas 5, 6 e 8:

... case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: if (PegaTexto(hwndDlg)) { MessageBox(hwndDlg,balaio,"Texto digitado",MB_OK); EndDialog(hwndDlg,1); } return 1; ...

Salve com |File/Save| o programa dlg2.c, compile e rode. Tchan, tchan, tchan, tchan - funciona! Agora experimente clicar em [OK] com o campo de edição vazio. Você vai perceber que não acontece nada - nem caixa de mensagem aparece, nem a caixa de diálogo é fechada. Isto é porque a função PegaTexto retorna 0 (ou falso), fazendo com que a linha de execução no caso do IDOK não entre na área do if, que o EndDialog não seja executado e que o valor de retorno seja 1 (ou verdadeiro).

Mas que programa mais mal educado! Imagine a situação do usuário que clica em [OK] e fica sem saber porque nada acontece. Vai achar que o programa pendurou ou, se entender de programação, vai dizer que nosso programinha é uma droga. Durma com um barulho desses!

Melhorando a interface

Para corrigir este comportamento inaceitável do nosso programa existem duas alternativas: ou chamamos uma nova caixa de mensagem para avisar o usuário que o campo de edição não pode estar vazio, ou desabilitamos o botão [OK], que só será habilitado quando houver texto no campo de edição. A primeira alternativa não oferece grandes novidades. A segunda é um novo desafio de programação. Então, vamos optar pela segunda.

O botão [OK] deve ter as seguintes características: no início do programa, estar desabilitado; se for digitado texto no campo de edição, deve ser habilitado; se o texto do campo de edição for apagado, deve ser desabilitado novamente. Quem é que está dando as cartas? É o campo de edição, e ele é apenas mais uma das janelas-filhas. Toca correr para nossa central de mensagens...

... case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: if (PegaTexto(hwndDlg)) { MessageBox(hwndDlg,balaio,"Texto digitado",MB_OK); EndDialog(hwndDlg,1); } return 1; case IDCANCEL: EndDialog(hwndDlg,0); return 1; case ID_EDICAO: return ConfereTexto(hwndDlg,wParam); } break; ...

Foram adicionadas a linhas 13, 14 e 15. Aqui cabe uma explicação. Quando comecei a escrever o texto para habilitar/desabilitar o botão [OK], o código começou a ficar mais extenso do que eu imaginava e a aparência do switch ficou horrível. Por isso, decidi criar uma função à parte, para deixar o código mais elegante e limpo. Vale como sugestão: toda vez que o código começar a virar uma maçaroca, crie uma função. A leitura do código fica mais fácil.

Bem, a função ConfereTexto tem esta cara. Observe os comentários (o que é uma boa prática de programação) cujas linhas são iniciadas com //:

int ConfereTexto(HWND hDlg,WPARAM wParam) { HWND hIdOk = GetDlgItem(hDlg,IDOK); switch (HIWORD(wParam)) { case EN_CHANGE: if (GetDlgItemText(hDlg,ID_EDICAO,balaio, sizeof(balaio))) { // Tem texto no campo de edição. Habilitar o botão IDOK EnableWindow(hIdOk,1); } else // sem texto, disabilitar o botão IDOK EnableWindow(hIdOk,0); break; } return 1; }

Na declaração switch estamos usando o HIWORD do wParam. É preciso explicar que wParam é um double word (também grafado como dword), ou seja, tem 32 bits. Um word é a metade de um dword e tem 16 bits. wParam carrega duas informações diferentes, uma nos 16 bits mais significantes (HIWORD) e outra nos 16 bits menos significantes (LOWORD). Nos bits do LOWORD encontramos a ID do controle que enviou a mensagem (o remetente) e nos bits do HIWORD encontramos a sub-mensagem de WM_COMMAND que o controle está enviando.

No nosso caso, LOWORD indicará ID_EDICAO e HIWORD indicará EN_CHANGE. Todas as mensagens oriundas de campos de edição possuem o prefixo EN, derivado de Edit Field Notification, e a tradução de CHANGE é mudar. Então, a cada mudança no campo de edição, uma mensagem EN_CHANGE será enviada através do LOWORD - botou uma letra, uma mensagem é enviada; tirou uma letra, a mesma coisa. É exatamente isto que vamos interceptar, ou seja, caso EN_CHANGE, então... então chamamos GetDlgItemText para verificar quantos caracteres há no campo de edição. Se houver mais do que 0 (zero) caracteres, habilitamos o botão. Se não houver caracteres, desabilitamos o botão.

Pra variar, precisamos do manipulador (handle) do botão IDOK para poder alterar suas propriedades. O manipulador foi obtido logo no início da função quando chamamos a GetDlgItem e guardamos o valor de retorno na variável hIdOk (que é do tipo HWND). Chamamos a função EnableWindow com os parâmetros hIdOk (o handle do botão IDOK) e um inteiro: 1 (TRUE) para habilitar o botão e 0 (FALSE) para desabilitá-lo.

Só falta um detalhe: o programa precisa começar com o botão IDOK desabilitado. Neste caso, isto deve ser feito antes da janela ser apresentada na tela, o que nos remete à função InitializaApp. Como já somos cobras em sanduiches de funções, mandamos ver o seguinte:

static int InitializeApp( HWND hDlg,WPARAM wParam, LPARAM lParam) { // Por foco no campo de edição SetFocus(GetDlgItem(hDlg,ID_EDICAO)); // Desabilitar o botão IDOK EnableWindow(GetDlgItem(hDlg,IDOK),0); return 1; }

Atualize o programa dlg2.c, salve-o, compile o código e execute o programa. Tá melhor, tá não?

Diálogo

Observações da vó

Sobre a interface com o usuário: a solução de desabilitar o botão OK até que foi boa, mas prefiro usar as caixas de mensagem que explicam exatamente o que está acontecendo. Um botão ou um item de menu desabilitados, na verdade, só impedem que sejam clicados e o usuário não é obrigado a saber porque isto está ocorrendo. Mensagens explícitas facilitam as coisas, mesmo quando óbvias (já me aconteceu de ter que abrir o código para verificar porque eu havia desabilitado determinado item de menu, pois não me lembrava mais depois de alguns meses wink

Bem, até agora nos preocupamos mais com o resultado da programação usando funções disponíveis. Está na hora de dar uma olhada nas principais bibliotecas que fornecem estas funções. Criamos nossas próprias funções e também fizemos uso de algumas variáveis. Não seria má idéia conhecer os tipos básicos, definições e declarações. Estes serão os assuntos do próximo tutorial.

биография Вадим Логофет как приготовить плов из курицы в мультиваркеофициальный никас сайт менюхарьков лобановскийангар быстровозводимыйкупить пудруполигон ооо

Informações adicionais