|
Neste tutorial vamos lidar com texto. Você deve estar pensando - "Escrever um texto ? Grande coisa, e daí ?". É que no Windows não se "escreve", se "pinta" o texto. Vamos usar a área cliente de uma janela e um contexto modelo (device context). Leia o tutorial e fique por dentro...
|
||||||||||||||||||||||
| PROJETO PINTANDO TEXTO | ||||||||||||||||||||||
|
||||||||||||||||||||||
| 1. Texto como objeto GUI | ||||||||||||||||||||||
|
Se você ainda se lembra, GUI significa Interface Gráfica do Usuário. A novidade é que o Windows trata texto como um gráfico, portanto, texto é um objeto gráfico ou objeto GUI. Cada caracter é um conjunto de pontos (pixels) dispostos de maneira que adquiram sua aparência peculiar. É por isso que "pintamos" o texto ao invés de escrevê-lo. Observe abaixo o caracter "a" dentro do círculo vermelho: não se vê pontinho nenhum. Logo acima está o mesmo "a" aumentado algumas vezes: os pixels começam a se delinear. Agora observe a ampliação maior: numa matriz de 10 x 10 pontos, alguns estão em azul formando a letra "a". Esta matriz servirá para quaisquer caracteres gráficos que quisermos montar para esta fonte. Aliás, a fonte usada no exemplo é a Courier New.
Podemos imaginar cada caracter da fonte como uma matriz de 10 x 10 pixels, com alguns "pintados" e outros "vazios". Para "pintar" uma frase, basta fazer uma sequência de matrizes, usando uma para cada caracter, com os respectivos pixels "cheios e vazios".
|
||||||||||||||||||||||
| 2. A área cliente de uma janela | ||||||||||||||||||||||
|
A tela do seu monitor pode apresentar vários programas simultaneamente. É claro que precisam existir regras para que um programa não "pinte" coisas na tela do outro. O Windows garante que um programa não invada a janela do outro limitando a área de pintura de cada janela à sua própria área (chamada de área cliente). A área cliente não tem o tamanho da janela. As bordas, por exemplo, não estão incluídas. Sabemos que a área cliente de uma janela não é constante: basta o usuário mudar suas dimensões que ela se modifica. É por isso que é preciso determinar a área cliente dinamicamente.
O sistema não permite a ação de "pixadores" - todas as pinturas são rigorosamente controladas. Primeiro é preciso obter uma autorização do Windows para pintar. O Windows então determina o tamanho da área cliente, a fonte, as cores e outros atributos e devolve um manipulador do modelo autorizado. Este modelo é chamado de contexto modelo.
|
||||||||||||||||||||||
| 3. O contexto modelo (device context) | ||||||||||||||||||||||
|
O contexto modelo é um estrutura de dados (veja mais em "Trabalhando com Estruturas") mantida internamente pelo sistema. Um contexto modelo geralmente está associado a um dispositivo, por exemplo, uma impressora ou uma tela de monitor. No caso do monitor, geralmente também está associado a uma janela em particular.
Alguns dos valores do contexto modelo são atributos gráficos, como cores e fontes. Quando solicitado, o sistema cria um contexto modelo com valores default. Estes valores podem ser mudados de acordo com as necessidades do programa e é para isso que o Windows devolve um manipulador.
Existem três formas de solicitar um manipulador de contexto modelo: call BeginPaint como resposta de uma mensagem WM_PAINT, call GetDC como resposta de outras mensagens e call CreateDC para criar um contexto modelo próprio.
Observação: após utilizar o contexto modelo é preciso liberá-lo. SEMPRE libere o contexto modelo na MESMA resposta de mensagem que você utilizou para obtê-lo.
|
||||||||||||||||||||||
| 4. A mensagem WM_PAINT | ||||||||||||||||||||||
|
O Windows envia uma mensagem WM_PAINT para uma janela para notificá-la de que é preciso repintar sua área cliente. Quando uma janela que estava coberta (ou semi-coberta) por outra é novamente mostrada integralmente, o Windows põe uma mensagem WM_PAINT na lista de mensagens da janela em questão. A janela, ao receber esta mensagem, repinta sua área cliente. Fica claro que, quando nós quisermos pintar algo na área cliente de uma janela, precisamos interceptar a mensagem WM_PAINT para efetuar o trabalho de pintura.
|
||||||||||||||||||||||
| 5. O Retângulo Inválido | ||||||||||||||||||||||
|
O Windows sempre define a menor área de uma janela que esteja precisando de uma repintura. É a menor área retangular que precisa ser atualizada, o chamado retângulo inválido. Repintando apenas o retângulo inválido, o sistema deixa de fazer muito trabalho inútil. Quando o Windows detecta um retângulo inválido na área cliente de uma janela, ele envia uma mensagem WM_PAINT para esta janela. Como resposta a esta mensagem, a janela pode obter uma estrutura paintstruct, a qual contém, entre outras informações, as coordenadas do retângulo inválido. Se formos processar uma mensagem WM_PAINT, no mínimo precisamos chamar o procedimento padrão do Windows (com DefWindowProc) ou validar o retângulo inválido com ValidateRect, caso contrário o Windows ficará enviando continuamente mensagens WM_PAINT.
|
||||||||||||||||||||||
| 6. A reposta à mensagem WM_PAINT | ||||||||||||||||||||||
|
A seguir encontram-se as etapas de uma resposta à mensagem WM_PAINT:
Não é preciso validar explicitamente o retângulo inválido - a chamada a BeginPaint faz isso por nós. Entre o par BeginPaint / EndPaint podemos fazer chamadas a funções para tarefas de pintura.
|
||||||||||||||||||||||
| 7. A janela com a frase "Assembly NumaBoa" | ||||||||||||||||||||||
|
O modelo do código fonte é o nosso velho conhecido, o da "Janelinha NumaBoa" que você encontra na caixa de ferramentas. Apenas o texto adicional será destacado e é claro que ele se encontra na nossa função gerenteMensagem:
|
||||||||||||||||||||||
| 8. Instanciando as variáveis locais | ||||||||||||||||||||||
|
Já vimos que vamos precisar de um manipulador do contexto modelo, uma estrutura PAINTSTRUCT e de uma estrutura RECT. O contexto modelo é gerenciado pelo sistema e precisamos apenas do seu manipulador: vamos chamá-lo de mCM. A estrutura PAINTSTRUCT contém 5 membros: 3 reservados apenas para uso interno do Windows, o que contém o manipulador do contexto modelo e o que contém a informação se o fundo deve ser repintado ou não. Não precisamos nos preocupar com esta estrutura porque, neste caso, apenas o Windows fará uso da mesma. Precisamos apenas instanciá-la que o Windows se encarrega de inicializar seus valores. Vamos chamá-la de ps. A estrutura RECT receberá o nome de eRet. Este tipo de estrutura define as coordenadas do canto superior esquerdo e do inferior direito de um retângulo: typedef struct _RECT { // rc
} RECT;
Vamos mudar um pouco a forma do procedimento da função gerenteMensagem apenas para não ficar na mesmice:
|
||||||||||||||||||||||
| 9. Iniciar o processo de pintura com BeginPaint | ||||||||||||||||||||||
|
Quando o programa é iniciado, uma das primeiras coisas que faz é "produzir" a janela principal. É claro que esta janela será pintada na tela, ou seja, receberá uma mensagem WM_PAINT. A partir daí, sempre que houver a necessidade de repintá-la, lhe será enviada a mesma mensagem. É aí que pegamos o gancho e solicitamos uma licença ao sistema para pintarmos nosso texto. Neste exemplo, a licença será solicitada através da chamada à função BeginPaint. Esta função, da user32.dll, prepara a janela especificada para pintura e inicializa a estrutura PAINTSTRUCT enviada com as informações necessárias: HDC BeginPaint(
);
Se tudo correr bem, o sistema nos devolve o manipulador do modelo do contexto. Passamos então o manipulador para a nossa variável local mCM:
|
||||||||||||||||||||||
| 10. Obtendo a área cliente da janela | ||||||||||||||||||||||
|
Com a função GetClientRect obtemos as coordenadas da área cliente de uma janela. As coordenadas cliente especificam os cantos superior esquerdo e inferior direito da área cliente. Como as coordenadas cliente são relativas ao canto superior esquerdo de uma área cliente, as coordenadas do canto superior esquerdo são (0,0). BOOL GetClientRect(
);
|
||||||||||||||||||||||
| 11. Desenhar o Texto | ||||||||||||||||||||||
|
Finalmente chegamos no texto... qual era mesmo? Nós sabemos que queremos "Assembly NumaBoa" mas nosso programa ainda não sabe. Precisamos criar uma variável que contenha a string e, aproveitando o embalo, vamos chamar a classe de "Janela" e personalizar o nome da nova janela: .DATA
Agora é só chamar a função DrawText, da user32.dll. DrawText é uma função API de alto nível para saída de texto (a prima pobre desta função é a TextOut). Esta função desenha um texto formatado dentro do retângulo especificado. Ela formata o texto de acordo com o método especificado (alinhando o texto, com quebra de linha, etc): int DrawText(
);
O parâmetro nCount especifica o número de caracteres da string. Se nCount for -1, então o parâmetro lpString é considerado como um ponteiro para uma string terminada em zero e DrawText calcula o número de caracteres automaticamente. O uFormat precisa de algumas explicações. uFormat pode ser a combinação de muitos valores diferentes, dos quais os mais comumente usados são:
Queremos nosso texto como linha única e centrado na horizontal e na vertical, portanto:
|
||||||||||||||||||||||
| 12. Desligar o processo de pintura com EndPaint | ||||||||||||||||||||||
|
Lembre-se de que precisamos liberar o manipulador do contexto modelo dentro da mesma resposta em que o criamos. Para não esquecer, eu costumo escrever o invoke BeginPaint e logo depois o invoke EndPaint. O miolo eu preencho posteriormente. Mas vamos lá. Já que a pintura está terminada, vamos liberar o manipulador do contexto modelo mCM chamando EndPaint: BOOL EndPaint(
);
|
||||||||||||||||||||||
| 13. O resultado | ||||||||||||||||||||||
![]() |
||||||||||||||||||||||
| ATÉLOGO | ||||||||||||||||||||||
|
Resumindo a história
É isso aí. E como não podia deixar de ser, o arquivo contendo todo o tutorial está disponível para download como tutNB05.zip (21 Kb).
|