Programação orientada a eventos no Windows – Segunda Parte

No artigo Programação orientada a eventos no Windows, discuti o fluxo de código típico num programa que disponibiliza uma interface gráfica padrão no sistema operativo Windows. Aqui vou apresentar um pequeno exemplo de aplicação simples. Relembro esse fluxo:

Para ilustrar os conceitos, vou considerar o exemplo de um pequeno cronómetro com quatro botões: Start, Stop, Split e Reset. Esta aplicação não poderá ser utilizada para cronometrar o tempo de forma rigorosa mas permite dar uma ideia de como são utilizados os eventos. O primeiro passo consiste em criar a janela da aplicação, a qual segue o seguinte fluxo:

criar a janela

Em primeiro lugar, inicializa-se a estrutura WNDCLASS com as propriedades gerais da janela tais como título da aplicação, estilos, a função que é chamada quando é despoletado um evento, o nome da classe, entre outros. O sistema oferece uma série de classes predefinidas como é o caso daquelas que descrevem botões, caixas de texto e outros controlos de utilização habitual. A janela é criada mediante a chamada à função CreateWindow que recebe o nome da classe registada entre outros parâmetros. Esta função também gera o evento WM_CREATE que é susceptível de ser tratado na função escolhida para codificar as acções associadas à aplicação. Depois da janela criada, esta é identificada por um manuseador do tipo HWND, o qual é utilizado pelas funções ShowWindow e UpdateWindow para mostrar a janela no ecrã e proceder à actualização do seu conteúdo. Esta actualização é feita no procedimento que codifica quais os objectos gráficos a serem apresentados sempre que a janela é desenhada. Isto consegue-se mediante o envio de um evento do tipo WM_PAINT.

Na função WinMain ainda se inicia o MessageLoop conforme o esquema anterior. Resta especificar as acções que aplicação deve tomar quando recebe um evento do utilizador ou do sistema. No caso do cronómetro, precisamos de definir quatro botões quando a janela é criada, de actualizar o valor correspondente à contagem do tempo sempre que passa um centésimo de segundo, começar a contagem, parar a contagem, congelar a contagem, reinicializar a contagem e sair da aplicação. Todas estas acções são implementadas no procedimento callback.

callback_reduced

Quando a janela é criada, envia um evento WM_CREATE que é usado para criar os botões de controlo. Botões são pequenas janelas cuja classe está predefinida e registada com o nome “Button”. Neste contexto é apenas necessário indicar a janela que os contém (o manuseador) bem como um inteiro que será usado para identificar o botão sempre que este gera um evento. Normalmente usa-se a directiva #define para definir esses inteiros. Quando o botão é premido, a aplicação envia o evento WM_COMMAND associando à mensagem o inteiro que identifica o botão. Neste fluxo temos definidos os inteiros para identificar o comando na notificação do WM_COMMAND:

#define ID_START 100
#define ID_STOP 101
#define ID_SPLIT 102
#define ID_RESET 103

Convém escolher números que não sejam usados por outros eventos. Sempre que a janela recebe o evento WM_PAINT (quando é movida, maximizada, …) são desenhados os botões e a contagem actual. Se o utilizador clica no x do canto superior direito da janela, a aplicação envia o evento WM_DESTROY que é usado para enviar uma mensagem de saída ao MessageLoop, qubrando-o.

Sempre que o utilizador clica no botão Start, é criado um Timer com a função SetTimer que envia um evento WM_TIMER a cada centésimo de segundo. Quando a função callback recebe esse evento, actualiza o contador e mostra-o na janela, enviando um evento WM_PAINT. O botão Stop elimina o Timer com a função KillTimer e a aplicação deixa de receber eventos WM_TIMER adquirindo um aspecto estático.

Observo que é necessário manter algumas variáveis globais que servem para traçar o estado da aplicação. Por exemplo, sempre que o utilizador clique Split é necessário que o cronómetro esteja em contagem e se este clica Reset é necessário que o cronómetro esteja parado. A informação do estado será guardado em variáveis globais.

Coloquei no google code um ficheiro com o código para o cronómetro, o qual foi compilado com sucesso no Visual C++ Express Edition 9.0. A aplicação fica com o seguinte aspecto.

cronometer

Relembro que não se trata de um cronómetro exacto uma vez que o evento WM_TIMER não é prioritário. Sempre que se tenta mover a janela, esta envia o evento WM_MOVE, o qual é processado pela função DefWindowProc. Sempre que o utilizador move a janela, o evento WM_TIMER é adiado criando lapsos temporais que podem ser resolvidos com a consulta ao relógio do sistema. No entanto, não é esse o objectivo a atingir neste texto.

Sobre Sérgio O. Marques

Licenciado em Física/Matemática Aplicada (Astronomia) pela Faculdade de Ciências da Universidade do Porto e Mestre em Matemática Aplicada pela mesma instituição, desenvolvo trabalho no PTC (Porto Technical Centre) - Yazaki como Administrador de bases-de-dados. Dentro o meu leque de interesses encontram-se todos os temas afins às disciplinas de Matemática, Física e Astronomia. Porém, como entusiasta, interesso-me por temas relacionados com electrónica, poesia, música e fotografia.
Esta entrada foi publicada em Sem categoria. ligação permanente.

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s