Академический Документы
Профессиональный Документы
Культура Документы
MFC Fundamentos
ANDR BERNARDI
Copyright 1999-2001 por Andr Bernardi. Todos os direitos reservados. Nenhuma parte do contedo dessa apostila pode ser reproduzida ou transmitida sob qualquer forma sem a permisso direta do autor.
Sobre o autor: Andr Bernardi Natural de Bragana Paulista. Engenheiro Eletricista pela Escola Federal de Engenharia de Itajub 1994, Mestre em Cincias da Engenharia Eltrica na rea de processamento digital de sinais biolgicos, pela EFEI 1999. Atua como desenvolvedor de software desde 1994. professor na Escola Federal de Engenharia de Itajub e Fundao de Ensino e Pesquisa de Itajub, onde ministra aulas de disciplinas de Programao Orientada a Objetos, usando C++ e Java, disciplinas de Desenvolvimento de Sistemas, Algoritmos e Estrutura de Dados.
Captulo 0 1 Introduo
1999-2001 Bernardi, A.
Captulo 0
1.2 Reutilizao
A reutilizao est baseada na padronizao a qual adotada h longa data em toda a indstria moderna, seja no projeto de carros, televisores, computadores, etc. A padronizao traz inmeras vantagens, entre elas podemos citar a seguintes:
as peas padres so mais baratas; so mais confiveis; geralmente so mais fceis de serem consertadas ou substitudas.
Na informtica a reutilizao de cdigos ainda praticada em escala muito reduzida e decorrente da iniciativas isoladas de alguns programadores e projetistas. So vrios os motivos para isso, entre eles:
existncia de uma Biblioteca e de um Sistema de Catlogo; facilidade para documentao; sistemtica rigorosa para testes; novas tcnicas para especificao de sistemas tendo em vista a reutilizao de mdulos; linguagem, ferramentas e ambientes de desenvolvimento que estimulem a adoo, em larga escala, de tais mtodos dentro das empresas; criao de novos geradores de sistemas que operem solucionando e combinando mdulos padres e que satisfaam as necessidades especficas das aplicaes; mudana administrativas e gerenciais nas empresas de modo a apoiarem e estimularem os criadores de mdulos padres.
A Orientao a Objetos traz vrios benefcios no desenvolvimento e manuteno de software. Para melhor compreenso dessas vantagens vamos dividi-las em dois grupos. No primeiro, que chamaremos de "Vantagens Diretas" colocamos aquelas que representam conseqncias diretas da adoo da Orientao a Objetos e, no segundo grupo, as "Vantagens Reais", estaro aquelas que so de fato o que procuramos com essa tecnologia.
Vantagens Diretas:
maior facilidade para reutilizao de cdigo e por conseqncia do projeto;
1999-2001 Bernardi, A.
Captulo 0
mais elevado de
utilizao de um nico padro conceitual durante todo o processo de criao de software; maior adequao arquitetura cliente/servidor; maior facilidade de comunicao com os usurios e com outros profissionais de informtica.
Vantagens Reais:
ciclo de vida mais longo para os sistemas; desenvolvimento acelerado de sistemas; possibilidade de se construir sistema muito mais complexos, pela incorporao de funes prontas; menor custo para desenvolvimento e manuteno de sistemas;
Abstrao - Consiste na concentrao nos aspectos essenciais. Preserva a liberdade de se tomar decises evitando, tanto quanto possvel comprometimento prematuro com detalhes. - o processo pelo qual a mente ou a inteligncia compreende o objeto, suas caractersticas e suas funcionalidade. Agregao - o relacionamento "parte-todo" ou "uma-parte-de" no qual os objetos que representam os componentes de alguma coisa so associados a um objeto que representa a estrutura inteira. Comportamento - como um objeto age e reage, em termos de mudana de seu estado e envio de mensagem. externamente visvel e comprovada atividade. Encapsulamento - Tambm chamado de ocultamento de informaes, o resultado de ocultar os detalhes de implementao de um objeto. o termo formal que descreve a juno de mtodos e dados dentro de um objeto de maneira que o acesso aos dados seja permitido somente por meio dos prprios mtodos do objeto. Nenhuma outra parte do programa pode operar diretamente em um dado do objeto. A comunicao de objetos ocorre exclusivamente por meio de mensagens explcitas. Tambm definido como um processo de "esconder" a complexidade interna de uma classe para suportar ou reforar a abstrao. 1999-2001 Bernardi, A. Captulo 0
Estado - so resultados cumulativos do comportamento do objeto - uma das possveis condies na qual o objeto existe - caracterizada pelas quantidades que so distintas de outras quantidades. Em qualquer ponto do tempo, o estado do objeto abraa todas as (usualmente esttica) propriedades do objeto mais os atuais (normalmente dinmico) valores dessa propriedade. Herana - um mtodo de derivar novas classes a partir de outras previamente existentes. A classe derivada herda a descrio de cada uma das classes bases, permitindo sua extenso atravs da adio de novas variveis e funes membro e usar funes virtuais. o compartilhamento de similitudes entre componentes preservando as diferenas. Representa generalizao e especializao, tornando explcitos os atributos e comportamentos comuns em uma hierarquia de classes. o mecanismo atravs do qual os atributos e o comportamento dos objetos de uma classe so assumidos pelos objetos de outra classe. uma relao entre uma super-classe e suas sub-classes, isto , o mecanismo pelo qual elementos mais especficos incorporam estrutura e comportamento de elementos mais gerais relacionados. H duas formas de se descobrir heranas: Generalizao Especializao
Mensagem - uma operao que um objeto executa sobre outro. Os termos mensagem, mtodo e operao so usualmente intercambiveis. Representa uma ao a ser praticada pelo objeto. Exemplo: Onde: MenuPrincipal = Objeto Seleciona = Mtodo Segunda Opo = Parmetro MenuPrincipal.Seleciona (Segunda Opo);
Mdulo - uma unidade de programa que contm declaraes, expressas num vocabulrio de uma linguagem de programao particular, que forma a realizao fsica de parte ou de todas as classes e objetos do projeto lgico do sistema. uma unidade de cdigos que serve como um bloco construdo para uma estrutura fsica de um sistema. Composto das seguintes partes: 1999-2001 Bernardi, A. Captulo 0
Interface - a viso externa de uma classe, objeto ou mdulo, os quais enfatizam suas abstraes enquanto esconde suas estruturas e os segredos de seus comportamentos. Implementao - a viso interna de uma classe, objeto ou mdulo, incluindo os segredos de seu comportamento.
Polimorfismo - Processos que executem funes semelhantes em componentes diferentes devem ser chamados pelo mesmo nome. a habilidade de duas ou mais classes responderem mesma solicitao, cada uma a seu modo. Conceito de permitir uma nica interface para mltiplas funes.
Objeto uma abstrao encapsulada (qualquer coisa, real ou abstrata) que inclui: informaes de estado (descrita por dados), um conjunto claramente definido de protocolos de acesso (mensagens que cada objeto responde) interesse acompanhar ou que seja til. Um objeto pode ser: uma pessoa, um material, uma instituio, um fato, um lugar, um conceito. tudo que aprendido pelo conhecimento que no o sujeito do conhecimento. tudo que manipulvel e/ou manufaturveis. tudo que perceptvel por qualquer sentido. tudo que externo ao sujeito. um objeto tem estado, comportamento e identidade. a estrutura e comportamento de objetos similares so definidos em suas classes. os termos instncias e objetos so intercambiveis. e possui um comportamento que se
Dois objetos exatamente iguais em atributos, relacionamentos e funes podem ser diferenciados atravs de seu identificador NICO, Exemplo: o nmero da matrcula do EMPREGADO, o CPF etc.
Tipos de Objetos:
Concretos (pessoa, lpis, carro, relgio etc.) Intangveis (hora, idia, organizao, projeto etc.) Papel (mdico, paciente, professor, aluno etc.) Relacional (casamento, parceira, propriedade etc.) Evento (venda, admisso, pane_no_sistema etc.) De Interface (janela, cone, string de caracteres etc.)
1999-2001 Bernardi, A.
Captulo 0
O comportamento de um objeto implementado por meio de mtodos que podem ser dos seguintes tipos: Relativos ao ciclo de vida; Recuperadores; Relativos administrao de armazenamento;
Instncia - Os objetos so instncias de uma classe. As propriedades de qualquer instncia (objeto) so determinadas pela descrio da classe qual pertence. Subclasse - um subconjunto de objetos pertencentes a uma classe que tm em comum em relao aos demais objetos desta classe: - dados adicionais e/ou, - operaes adicionais. Classe e Objetos - um conjunto de objetos que so descritos pelos mesmos dados e possuem o mesmo comportamento. conjunto de objetos que compartilham uma estrutura e um comportamento comum. o termo classe e type so usualmente (mas no sempre) intercambiveis uma classe tem conceito ligeiramente diferente de um tipo, no qual ela enfatiza a classificao da estrutura e comportamento. uma classe um tipo definido pelo usurio que contm o molde, a especificao para os objetos, assim como o tipo inteiro contm o molde para as variveis declaradas como inteiros. a classe envolve, associa funes e dados controlando o acesso a estes. definir classe implica em especificar os seus atributos (dados) e suas funes (mtodos).
As interfaces de uma classe ou objetos so representadas atravs de seus mtodos e de suas funcionalidades. Em resumo, objetos so instncias de classes que respondem mensagens de acordo com mtodos determinados pelo protocolo de descrio de classes. Os objetos tambm tm variveis de estado definidas no protocolo de descrio de classe que podem ter valores iguais ou diferentes nas vrias instncias da classe.
1999-2001 Bernardi, A.
Captulo 0
Uma classe determina as caractersticas de um objeto: propriedades, eventos e mtodos relacionados. Propriedades: Um objeto tem certas propriedades, ou atributos. Para o exemplo acima, um telefone possui cor e tamanho. Quando um telefone colocado em sua casa ou escritrio, ele ter uma certa posio sobre uma mesa. O receptor pode estar no ou fora do gancho. Objetos criados com o Visual C++, contm certas caractersticas que so determinadas pela classe em que o objeto est baseado. Estas propriedades podem ser fixadas a em seu desenvolvimento ou em tempo de execuo. Por exemplo um check box, poder conter as seguintes propriedades, descritas na tabela abaixo: Propriedade Titulo Habilitado Esquerda Visvel Descrio Um texto descritivo antes do check box Quando o check box puder ser selecionado pelo usurio. Alinhamento a esquerda do check box Quando o check box est visvel na janela
Eventos: Cada objeto reconhece e pode responder a certas aes chamadas eventos. Um evento uma atividade especfica e pr-determinada, iniciada tanto pelo usurio quanto pelo sistema. Na maioria dos casos eventos so gerados pela interao do usurio. Por exemplo, para o telefone, um evento disparado toda vez que o usurio retira o fone do gancho. Eventos so gerados quando o usurio pressiona um boto para discar, etc. Na programao para Windows, uma ao do usurio que pode provocar o disparo de um evento pode ser um click ou movimento do mouse, ou pressionar uma tecla do teclado. Quando um erro ocorre ao inicializar um objeto um evento do sistema disparado. 1999-2001 Bernardi, A. Captulo 0
10
A tabela a seguir mostra alguns eventos relacionados com o check box. Evento Click do mouse GotFocus LostFocus Mtodos: Mtodos so funes que esto associadas aos objetos. Suas chamadas so feitas atravs de mensagens. Um mtodo pode estar relacionado a um Evento. Exemplo se for escrito um mtodo para responder ao evento de click do mouse, este ser chamado toda vez que o boto do mouse for pressionado. Mtodos podem existir independente de eventos, estes mtodos so chamados explicitamente dentro do cdigo. A tabela a seguir mostra alguns mtodos relacionados com o check box. Mtodo Atualizar SetFocus Descrio O valor do check box atualizado para refletir as alteraes que possam Ter ocorrido na base de dados subjacente. O foco atual passado ao check box como resultado de um usurio pressionar a tecla TAB at o check box ser selecionado. A classe envolve, associa, funes e dados, controlando o acesso a estes, defin-la implica em especificar os seus atributos (dados) e suas funes membro (mtodos). Descrio Usurio pressiona o check box Usurio seleciona o check box por um click ou tab. Usurio seleciona outro controle
Exemplos:
1. Um programa que utiliza uma interface controladora de um motor eltrico provavelmente definiria a classe motor. Os atributos desta classe seriam: temperatura, velocidade, tenso aplicada. Estes provavelmente seriam representados na classe por tipos como float ou long . As funes membro desta classe seriam funes para alterar a velocidade, ler a temperatura, etc.
2. Um programa editor de textos definiria a classe pargrafo que teria como um de seus atributos uma string ou um vetor de strings, e como funes membro, funes que operam sobre estas strings. Quando um novo pargrafo digitado no texto, o editor cria a partir da classe pargrafo um objeto contendo as informaes particulares do novo texto. Isto se chama instanciao ou criao do objeto.
1999-2001 Bernardi, A.
Captulo 0
11
3. Um programa de controle de vendas definirias as classes Cliente, Venda, Produto, Fatura, Vendedor. As classes de Cliente e Venda teriam os seguintes dados e mtodos:
Classe Atributos Mtodos
id_cliente nome_cliente Cliente endereco pessoa_autorizada Status id_cliente Venda id_vendedor data_venda produto
12
O motor precisa conhecer a sua sada serial, a sua ligao com o "motor do mundo real". Suponha uma representao em hexadecimal do atributo endereo de porta serial, um possvel nome para o atributo: enderecomotor. No se preocupe em saber como usar a representao hexadecimal. Alterao do valor da velocidade: Internamente o usurio da classe motor pode desejar alterar a velocidade, cria-se ento o mtodo (em C++ funo membro): void altera_velocidade(int novav); . O cdigo anterior corresponde ao cabealho da funo membro, ela definida junto com a classe motor, associada a ela. O valor de retorno da funo void (valor vazio), poderia ser criado um valor de retorno (int) que indicasse se o valor de velocidade era permitido e foi alterado ou no era permitido e, portanto no foi alterado. No faz sentido usar, chamar, esta funo membro separada de uma varivel do tipo motor, mas ento porque na lista de argumentos no se encontra um motor? Este pensamento reflete a maneira de associar dados e cdigo (funes) das linguagens procedurais. Em linguagens orientadas a objetos o cdigo e os dados so ligados de forma diferente, a prpria declarao de um tipo definido pelo usurio j engloba as declaraes das funes inerentes a este tipo. Note que no fornecemos o cdigo da funo, isto no importante, por hora a preocupao com a interface definida pela classe: suas funes membro e dados membro. Apenas pense que sua interface deve ser flexvel de modo a no apresentar entraves para a criao do cdigo que seria feita numa outra etapa. Nesta etapa teramos que imaginar que o valor numrico da velocidade deve ir para o conversor onde ir se transformar numa diferena de potencial a ser aplicada nos terminais do motor, etc.
13
dados e os prottipos em um arquivo de cabealho e colocar as definies das funes em um ou mais arquivos de compilao. Uma terceira opo incluir a descrio completa da classe em um nico arquivo que tambm contenha o programa executvel. Esta ltima escolha indesejvel quando outros usurios forem utilizar esta classe, o que geralmente acontece. Uma descrio de classe formal comea com a palavra reservada class (seguida de um abre chaves { ) e termina com um fecha chaves e um ponto e virgula. ( }; ) conforme o exemplo abaixo. A descrio de classe tem trs sees cada uma delas contendo campo de dados e funes membros. As trs sees so: privada ( private: ), protegida ( protected: ) e pblica ( public: ). Os dados e as funes membros, na seo privada podem ser acessados apenas pelo protocolo da descrio de classe. Os dados e as funes membros na seo pblica podem ser acessados pelo cdigo de qualquer arquivo usurio que inclua a descrio de classe. As variveis (objetos) declaradas como do tipo classe tm acesso direto apenas seo pblica de suas descries de classe. A categoria protegida tem aplicao no uso de classes derivadas (Herana).
Os construtores so identificados como funes membros cujos nomes so iguais ao nome da classe. A listagem acima mostra trs construtores para a classe CNomeClasse . A sobrecarga do nome do construtor precisa satisfazer as mesmas exigncias das outras funes, isto , as listas de parmetros precisam ser diferentes. Um construtor pode ter uma lista de parmetros void. Os construtores podem fornecer valores default para um ou mais de seus parmetros. A funo membro ~CNomeClasse um destrutor. Ela precisa ter uma lista de parmetros void. Pode ter um corpo de cdigo executvel se necessrio. Na listagem, apenas prottipos so fornecidos para o Construtor1, Construtor2, Construtor3, destrutor,
1999-2001 Bernardi, A.
Captulo 0
14
funcao1 e funcao2. Tanto prottipos como definies so fornecidos para funcao3. Quando a definio de uma funo membro est incluida na descrio de classe, ela tratada como cdigo inline. As restries de implementao geral pedem que o cdigo inline no contenha nenhuma construo de controle, exceto if ( como por exemplo do, for, while, break, continue, goto, switch). Recomenda-se que o cdigo inline seja usado com ponderao e apenas no caso de implementaes relativamente simples de funes membros. Os detalhes relativos s definies de Construtor1, Construtor2, Construtor3, destrutor, funcao1 e funcao2, so fornecidos fora da descrio formal da classe. Eles pecisam ento ser identificados com suas classes, conforme indica a listagem abaixo. Estes detalhes podem estar contidos no mesmo arquivo da descrio formal da classe ou em um outro arquivo. Se forem implementados em um outro arquivo, o arquivo cabealho precisa estar incluido, como mostra a listagem abaixo. As definies isoladas de funes so identificadas com a classe apropriada colocando-se o qualificador CNomeClasse:: antes do nome de cada funo. Definies Externas para Funes Membros de uma Descrio de Classe
// Contedo do arquivo para definies externas de funes membros #include NomeClasse.h tipoRetorno CNomeClasse::funcao1( lista parametros ) { instrucoes; }; tipoRetorno CNomeClasse::funcao2( lista parametros ) { instrucoes; }; CNomeClasse::CNomeClasse ( lista parametros a) { instrucoes; }; CNomeClasse::CNomeClasse ( lista parametros b) { instrucoes; }; CNomeClasse::CNomeClasse ( void ) { instrucoes; }; CNomeClasse::~CNomeClasse ( void ) { instrucoes; }; // Construtor 1
// Construtor 2
// Destrutor
Se algum tentar incluir campos de dados no arquivo externo que parte de uma descrio de classe, ocorrer um erro. Todas as declaraes precisam estar na descrio formal da classe. Apenas as definies das funes membros e membros de dados estticos podem ser externas descrio formal da classe. 1999-2001 Bernardi, A. Captulo 0
15
Muito j foi escrito sobre a aceitao de Microsoft Windows e os benefcios de sua interface grfica com o usurio (GUI). Esta introduo resume o modelo de programao Windows (Win32 em particular) e mostra como os componentes do Visual C++ trabalham em conjunto para lhe ajudar a escrever aplicaes para Windows. No decorrer do captulo, voc aprender algumas coisas novas sobre o Windows.
1999-2001 Bernardi, A.
Captulo 1
16
operacional para adquirir as entradas do usurio, mas um programa baseado em Windows o processa as entradas do usurio por mensagens do sistema operacional. NOTE: Muitos ambientes de desenvolvimento para Windows, inclusive Microsoft Visual C++ verso 5.0 com a Microsoft Foundation Class (MFC) verso 4.21, simplifica a programao ocultando a funo WinMain e estruturando o processo de manipulao de mensagens. Quando voc usa a biblioteca MFC, voc no precisa escrever uma funo WinMain mas essencial que voc entenda o vnculo entre o sistema operacional e seus programas. A maioria das mensagens do Windows so estritamente definidas e aplicam-se a todos os programas. Por exemplo, a mensagem WM_CREATE enviada quando uma janela est sendo criada, a mensagem WM_LBUTTONDOWN enviada quando o usurio aperta o boto esquerdo do mouse, a mensagem WM_CHAR enviada quando o usurio digita um caractere, e a mensagem de WM_CLOSE enviada quando o usurio fecha uma janela. Todas as mensagens tm dois parmetros de 32-bit que carregam informaes como as coordenadas do cursor, cdigo da tecla, e assim por adiante. Windows envia mensagens de WM_COMMAND janela apropriada em resposta para selees do usurio no menu, pressiona um boto em um dilogo, etc. Os parmetros da mensagem Command variam e dependendo layout do menu da janela. Voc pode definir suas prprias mensagens que seu programa pode enviar a qualquer janela no desktop. Estas mensagens definidas pelo usurio na verdade fazem com que o C++ se parea um pouco como Smalltalk. No se preocupe ainda como estas mensagens so conectadas a seu cdigo. Isso o trabalho da Estrutura de Aplicao (Application Framework). Entretanto, esteja atento que o processamento de mensagens do Windows impe muitas exigncias na estrutura de seu programa. No tente forar seu programa Windows para ele se parecer com seus programas velhos de MS-DOS. Estude os exemplos neste curso, bem como os exemplos do Visual C++ e ento estar preparado para iniciar em sua nova filosofia.
17
instrues de entrada/sada apropriadas. A GDI quase to rpida quanto o acesso direto de vdeo, e permite a diferentes aplicaes escritas para Windows compartilhar a exibio na tela.
1999-2001 Bernardi, A.
Captulo 1
18
Os desenvolvedores de MFC tiveram sucesso combinando todas as classes que compe a estrutura das aplicaes em algumas DLLs. Isto significa que voc pode vincular esttica ou dinamicamente as classes da estrutura das aplicaes em seu aplicativo.
1999-2001 Bernardi, A.
Captulo 1
19
Uma avaliao dos componentes do Visual C++, lhes ajudaro a adquirir seus portes antes que voc comece com a estrutura das aplicaes. A Figura 1 a seguir mostra uma viso geral do processo de construo (build) de um aplicativo no Visual C++.
1999-2001 Bernardi, A.
Captulo 1
20
Compilao de Recursos
Arquivo de recurso (RC)
Compilador de Recursos
Arquivos de Cabealhos MFC Arquivo RES
Compilador
Arquivos OBJ
Linker
Executvel (EXE)
Em um projeto do Visual C++ 6.0, no h makefile (com a extenso MAK) at que voc especifique ao sistema para exportar um. Um arquivo de projeto no formato texto (com a extenso DSP) serve para o mesmo propsito. Um outro arquivo texto para o workspace (com a extenso DSW) possui uma entrada para cada projeto que compe este workspace. possvel ter vrios projetos dentro de um mesmo workspace, porm todos exemplos deste curso tero apenas um projeto por workspace. Para trabalhar com um projeto j existente, abra o arquivo com a extenso DSW dentro do Developer Studio e ser possvel manipular este projeto.(editar compilar, etc.). Arquivos intermedirios tambm so criados pelo Developer Studio. A tabela a seguir contm uma lista dos arquivos que so gerados pelo Developer Studio para cada workspace: Extenso APS BSC Descrio Utilizado pelo Resouce View Arquivo de informaes do Browser
1999-2001 Bernardi, A.
Captulo 1
21
Utilizado pelo ClassWizard Arquivo do Project* Arquivo do Workspace* makefile externo Utilizado pelo ClassView Armazena as configuraes do workspace Arquivo de log do Build
WizardBar
Plataforma de Construo
Cdigo Fonte
Janela WorkSpace
do
22
editar cones, bitmaps, e strings. O editor de dilogos permite ainda que sejam adicionados controles ActiveX, controles padres do Windows os novos Windows common controls. Usualmente, cada projeto contm um arquivo de recurso script (RC) no formato texto, que descreve os menu, dilogos, string, e aceleradores do projeto. O arquivo RC possui declaraes #include para trazer recursos de outros subdiretrios. Estes recursos incluem itens especficos do projeto, como arquivos de bitmap (BMP) e de cone (ICO), e recursos comum a todo programa em Visual C++ tal como strings de mensagem de erro. A edio do arquivo RC fora do editor de recurso no recomendada. Os editores de recurso tambm podem processar arquivos EXE e DLL, assim pode-se utilizar o clipboard para roubar recursos, como bitmaps e cones de outras aplicaes do Windows.
2.5 O Linker
O linker processa os arquivos OBJ e RES, produzidos pelo compilador C/C++ e o compilador de recursos, e acessa os arquivos LIB para os cdigos da MFC, runtime Library, e do Windows. responsvel pela criao do arquivo executvel EXE do projeto. A opo de link incremental minimiza o tempo de execuo quando pequenas mudanas so feitas nos arquivos de cdigos fontes. Os cabealhos dos arquivos da MFC contm blocos especiais #pragma (diretivas de compilao) que especificam os arquivos LIB que so necessrios, assim voc no tem que contar explicitamente para o linker quais bibliotecas ele deve ler.
1999-2001 Bernardi, A.
Captulo 1
23
2.6 O Debugger
Caso seu programa funcione da primeira vez, no necessrio usar o debugger. Todos ns poderiamos precisar dele de vez em quando. O debugger do Visual C++ tem melhorado continuamente, contudo no fixa de fato os bugs. O debugger trabalha junto com o Developer Studio para assegurar que os breakpoints so armazenados em disco. Existem botes na barra de ferramentas para inserir e remover breakpoints e controlar a execuo passo a passo. A Figura 3 ilustra o debugger do Visual C++ em ao. Notar que as janelas Variables e Watch podem expandir um ponteiro de um objeto para mostrar todos seus membros das classes derivadas e base. Se o cursor do mouse for posicionado sobre uma varivel, o debugger mostra seu valor em uma pequena janela (Tooltip). Para debugar um programa, necessrio constru-lo (build) com as opes e de compilador e linker setadas para gerar informaes de debug.
Figura 3 O Debugger em Ao
2.7 AppWizard
O gerador de cdigo que cria todo o esqueleto de um aplicativo baseado em Windows chamado de AppWizard. Os nomes das classes geradas, e de seus arquivos de cdigo fonte, baseado no que foi especificado em suas caixas de dilogo. O AppWizard ser utilizado exaustivamente por todo este curso, para gerar os programas de exemplo. 1999-2001 Bernardi, A. Captulo 1
24
No confunda o AppWizard com os antigos geradores de cdigo, que geravam todo o cdigo para um aplicativo. O cdigo gerado pelo AppWizard minimalista; a funcionalidade est dentro das classes bases da Estrutura das Aplicaes. O AppWizard permite que voc inicialize uma aplicao nova rapidamente.
2.8 ClassWizard
ClassWizard um programa (implementado como uma DLL) que est acessvel atravs do menu View do Developer Studio. O ClassWizard o alivia da maante funo de manter e gerar um cdigo de classe no Visual C++. Se precisar de uma classe nova, de uma funo virtual, ou uma nova funo de manipulador de mensagem nova? O ClassWizard escreve os prottipos, os corpos de funo, e (se necessrio) o cdigo para unir a mensagem do Windows para a funo. ClassWizard pode atualizar cdigos de classe j escritos, assim pode-se evitar os problemas de manuteno comum a geradores de cdigo ordinrios. Algumas caractersticas do ClassWizard esto disponveis na WizardBar do Developer Studio, como mostrado na Figura 2.
1999-2001 Bernardi, A.
Captulo 1
25
NOTA: Se simplesmente uma linha de cdigo mudar de posio, em qualquer um dos cdigos fontes que pertenam ao projeto, o banco de dados para o browser tem que ser re-gerado pelo Developer Studio, o que faz com que haja um aumento no tempo de compilao. Alm do Browser, o Developer Studio tem a opo de utilizar a janela ClassView do Workspace que no depende da gerao de uma base de dados para o browser. Ela uma tree view com todas as classes do projeto, mostrando as funes membros e variveis membros. Basta um duplo click em um de seus elementos, e o cdigo fonte onde est a declarao ficar visvel imediatamente. A janela ClassView no contm informaes sobre a hierarquia das classes que est disponvel no browser.
1999-2001 Bernardi, A.
Captulo 1
26
Seja qual for o modo que o help online foi acessado, possvel copiar qualquer texto de ajuda para o clipboard para incluso em seu programa. OBS: A janela InfoViewer foi substituda pelo aplicativo da MSDN.
2.12 A Galeria
A galeria do Developer Studio permite que se compartilhem componentes de software entre diferentes projetos. A Galeria gerencia trs tipos de mdulos: ActiveX controls quando instalado um controle ActiveX (OCX - OLE control), uma entrada feita dentro do Registro do Windows. Todos os controles ActiveX registrados aparecem na janela da Galeria, e podem ser selecionados em qualquer projeto. C++ source modules quando uma nova classe escrita, esse cdigo pode ser adicionado na Galeria. Esse cdigo pode ser selecionado e copiado nos outros projetos. Recursos tambm podem ser adicionados a Galeria. Componentes do Developer Studio - A Galeria contm ferramentas que podem ser usadas para adicionar caractersticas nos projetos. Tal ferramenta pode inserir novas classes, funes, membros de dados, e recursos em um projeto existente. Alguns componentes so fornecidos pela Microsoft (processamento de tempo Inativo, apoio de Paleta, e Splash Screen, por exemplo) como parte do Visual C++. Outros so fornecidos por outras firmas de Software.
1999-2001 Bernardi, A.
Captulo 1
27
DICA: Se voc decidir utilizar alguns dos componentes da Galeria Developer Studio, experimente primeiro em um projeto bobo para ver se o que voc realmente quer. Caso contrrio, pode ser difcil de remover o cdigo gerado de seu projeto regular. Todos os cdigos gerados para a Galeria podem ser importados de um ou exportados para um arquivo OCX. Estes arquivos fazem parte de um novo meio de distribuio e compartilhamento para componentes do Visual C++.
3 Microsoft
Foundation
Class
Library
Application
Framework (Overview)
As prximas sees: Porque utilizar uma Estrutura de Aplicaes? O que uma Estrutura de Aplicaes ? Mapeamento de Mensagens na MFC Library Documents e Views o introduzem na estrutura das aplicaes da biblioteca Microsoft Foundation Class verso 4.2.1 (a MFC) e explica seus benefcios. Um primeiro exemplo mostrado na pgina 30 onde possvel introduzir parte da operacionalidade da MFC Library na programao para Microsoft Windows e comear a entender o conceito de estrutura de aplicao. Teoria mantida a um mnimo aqui, mas as sees sobre mapeamento de mensagens e em documents e views contem informaes importantes que o ajudar com os exemplos que viro a seguir.
1999-2001 Bernardi, A.
Captulo 1
28
Programar em C com a Win32 API, Escrever sua prpria biblioteca de classes em C++ para o Windows que utilize a Win32 API, Utilizar a estrutura de aplicaes da MFC, Utilizar outra estrutura de aplicaes baseada em Windows como a Object Windows Library (OWL) da Borland. Se voc est no nvel zero, qualquer opo envolve uma curva de aprendizagem grande. Se voc j um programador Win16 ou Win32, voc ainda ter uma curva de aprendizagem com a MFC Library. Assim que benefcios podem justificar este esforo? A titulo de curiosidade a MFC foi totalmente aceita pelo mercado e at mesmo foi usada por outro desenvolvedor de compilador como Symantec. Bem como pela maioria de fabricantes de software profissionais do mercado como a Oracle, AutoDesk, entre outras. A prpria Microsoft utiliza o Visual C++ para desenvolver seus aplicativos como, por exemplo, o pacote do Office e at mesmo o Internet Explorer. Ainda assim uma boa idia, navegar pelas caractersticas desta escolha de programao. A MFC Library a Microsoft Windows API em C++. Assumindo a premissa que a linguagem C++ agora um padro para plataforma de desenvolvimento de aplicativos profissionais, voc teria que dizer que natural para Windows ter uma interface de programao em C++. Que interface melhor h, do que aquela produzida pelo pessoal da Microsoft, criador de Windows? Essa interface a MFC Library. Aplicativos que usam uma Estrutura de Aplicaes possuem uma forma padronizada. Qualquer programador que comea em um projeto grande desenvolve algum tipo de estrutura para o cdigo. O problema que a estrutura de cada programador diferente, e difcil para um membro novo do time aprender a estrutura se conformar a isto. A estrutura de aplicao da MFC Library inclui sua forma prpria para uma aplicao uma que aprovado em muitos ambientes de software e em muitos projetos. Se voc escreve um programa para Windows que usa a MFC, voc pode se aposentar seguramente para uma ilha caribenha e saber que seus subordinados podem manter e aumentar seu cdigo facilmente em casa. No pense que a estrutura da MFC torna seus programas inflexveis. Com a MFC, seu programa pode chamar funes Win32 a qualquer hora a, assim voc poder tirar proveito do Windows. As ferramentas do Visual C++ reduzem a tarefa de codificar. O editor de recursos do Developer Studio, AppWizard, e ClassWizard reduzem significativamente o tempo necessrio para escrever cdigo que especfico da sua aplicao. Por exemplo, o editor de recursos cria um arquivo de cabealho que contm valores constantes de #define 1999-2001 Bernardi, A. Captulo 1
29
para os identificadores. AppWizard gera o esqueleto do cdigo para sua aplicao inteira, e ClassWizard gera prottipos e corpos de funo para manipuladores de mensagem.
30
matemtica, por exemplo, poderia executar operaes matemticas comuns e uma biblioteca de classe de comunicaes poderiam apoiar a transferncia de dados em um link serial. s vezes voc constri objetos das classes providas; s vezes voc deriva suas prprias classes - tudo depende do design particular da biblioteca de classes. Uma estrutura de aplicaes um super conjunto de bibliotecas de classes. Uma biblioteca ordinria um conjunto isolado de classes projetadas para ser incorporada em qualquer programa, mas uma Estrutura de Aplicaes define a estrutura do programa. A Microsoft no inventou o conceito de Estrutura de Aplicaes. Surgiu no Mundo acadmico, e a primeira verso comercial foi a MacApp para o Apple da Macintosh. Desde que a MFC 2.0 foi introduzida, outras companhias, inclusive Borland, lanaram produtos semelhantes.
1999-2001 Bernardi, A.
Captulo 1
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos #include <afxwin.h> // biblioteca da MFC onde esto declaradas as classes bases #include myapp.h CMyApp theApp; BOOL CMyApp::InitInstance() { m_pManWnd = new CMyFrame(); m_pManWnd->ShowWindow(m_nCmdShow); m_pManWnd->UpdateWindow(); return TRUE; } CMyFrame::CMyFrame() { Create(NULL Aplicativo MYAPP) ; } CMyFrame::OnLButtonDown(UINT nFlags, CPoint point) { TRACE(Entrando em CMyFrame::OnLButtonDown - %lx, %d, %d\n, (long) nFlags, point.x, point.y); } CMyFrame::OnPaint() { CPaintDC dc(this); dc.TextOut(0,0,Hello world!); }
31
Aqui esto alguns elementos desse programa: A funo WinMain Lembrar que o Windows requer que os aplicativos tenham a funo WinMain. Aqui WinMain no visvel porque est encapsulada dentro da estrutura das aplicaes. A classe CMyApp Um objeto da classe CMyApp representa um aplicativo. O programa define um objeto global do tipo CMyApp, theApp. A classe base CWinApp determina a maioria do comportamento de theApp. Inicializao do aplicativo Quando o usurio inicializa o aplicativo, o Windows chama a funo WinMain interna da estrutura de aplicao, e WinMain procura pelo construtor do objeto global do aplicativo da classe derivada de CWinApp. No esquecer que num programa em C++, objetos globais so construdos antes do programa principal ser executado. A funo membro CMyApp::lnitlnstance Quando a funo WinMain procura o objeto aplicativo, a funo membro virtual InitInstance chamada, que faz as chamadas necessrias para construir e exibir a janela da mainframe do aplicativo. Voc tem que sobrecarregar a InitInstance em sua classe derivada da aplicao porque o CWinApp que a classe base no conhece que tipo de janela principal voc quer chamar.
1999-2001 Bernardi, A.
Captulo 1
32
A funo membro CWinApp::Run A funo Run est encapsulada na classe base, mas despacha as mensagens da aplicao para suas janelas e assim mantm o funcionamento da aplicao. WinMain chama Run depois que chama InitInstance. A classe CMyFrame Um objeto da classe CMyFrame representa a janela da mainframe do aplicativo. Quando o construtor chama a funo membro Create da classe base CFrameWnd, o Windows cria a estrutura da janela e a application framework a vincula a um objeto em C++. As funes ShowWindow e UpdateWindow, tambm membros da classe base, devem ser chamadas para exibir a janela. A funo CMyFrame::OnLButtonDown - Isto uma pr-estria da capacidade de manipular mensagens da MFC. O evento pressionar o boto esquerdo do mouse mapeado map para uma funo membro de CMyFrame. Voc aprender os detalhes das mensagens coma a biblioteca MFC mais adiante. Por enquanto aceite que esta funo chamada quando o usurio aperta o boto de esquerdo do mouse. A funo invoca a macro TRACE da MFC para exibir uma mensagem na janela de depurao. A funo CMyFrame::OnPaint - A estrutura das aplicaes chama esta importante funo membro mapeada na classe CMyFrame toda vez que for necessrio redesenhar a janela: ao inicializar o programa, ao redimensionar um janela e quando qualquer parte da janela for revelada aps estar sobre outra. A declarao de CPaintDC relaciona-se com a Interface de Dispositivo de Grficos (GDI) e explicado em mais adiante. A funo TextOut exibe Hello, world!. Finalizao do Aplicativo - O usurio termina a aplicao fechando a janela da mainframe. Esta ao inicia uma sucesso de eventos que termina com a destruio do objeto CMyFrame, a sada de Run e a sada de WinMain, e a destruio do objeto CMyApp. Examine o cdigo fonte do exemplo novamente. A maior parte da funcionalidade da aplicao est nas classes bases da MFC CWinApp e CFrameWnd. Ao escrever MYAPP, ns seguimos algumas regras simples de estrutura e escrevemos funes chaves em nossas classes derivadas. C++ nos deixa obter emprestado muito cdigo sem precisar copiar isto. Pense nisto como uma sociedade entre ns e a estrutura das aplicaes. A application framework prove a estrutura, ns provemos o cdigo que faz a aplicao ser nica. Agora voc est comeando a ver por que a application framework mais do que uma biblioteca de classes. A application framework no faz s a estrutura de um aplicativo, mas tambm fornece mais que classes bases C++. Voc j viu como a funo encapsulada WinMain trabalha. Outros elementos suportam o processamento de mensagem, diagnsticos, DLLs, e assim sucessivamente.
1999-2001 Bernardi, A.
Captulo 1
33
7 Documents e Views
O exemplo acima usou um objeto application e um objeto frame window. Muitos aplicativos baseados na MFC Library sero mais complexos. Tipicamente, contero alm das classes application e frame, mais duas outras classes que representam o "document" e a
1999-2001 Bernardi, A.
Captulo 1
34
"view". Esta arquitetura document-view o corao da estrutura das aplicaes e est baseado nas classes de Model/View/Controller do mundo do Smalltalk. Um document um objeto de dados que manipulado pelo usurio em uma seo de edio. criado pelo comando do menu File New ou Open e so tipicamente armazenados em arquivos. Uma view um objeto janela que permite que o usurio interaja com o documento ao qual ela est associada. Em termos gerais, a arquitetura de document-view separa os dados, da viso pelo usurio dos dados. Um benefcio bvio vises mltiplas dos mesmos dados. Considere um documento que consiste no preo de um ms de citaes acionrias armazenado em disco. Suponha que existam uma viso de tabela e uma viso grfica dos dados. O usurio atualiza valores na janela da tabela, e a janela do grfico muda porque ambas as janelas exibem a mesma informao (mas em vises diferentes). Em aplicativos da MFC Library, documents e views so representados por instncias de classes C++. A classe base do document interage com menu File Open e File Save; a classe de document derivada faz a leitura e escrita dos dados do objeto de documento. (A estrutura das aplicaes faz a maioria do trabalho de exibir o dilogo de abertura de Arquivos e gravao de arquivos e abrindo, fechando, lendo, e escrevendo arquivos.) A classe base view representa uma janela que contida dentro de uma janela de frame; a classe de viso derivada interage com sua classe de documento associada e faz a exibio da aplicao e impresso. As classes view derivada e base manipulam as mensagens de Windows. A MFC libray organiza todas as interaes entre documentos, views, frame-window, e o objeto application, principalmente por funes virtuais. No pense que um objeto de documento deve ser associado com um arquivo de disco que lido completamente na memria. Se um "documento" real fosse um banco de dados, por exemplo, pode-se sobrecarregar as funes membro que servem para selecionar o documento a funo que responde ao menu File Open para mostrar uma lista de bancos de dados em vez de uma lista de arquivos.
1999-2001 Bernardi, A.
Captulo 1
35
Neste Captulo abordado um dos componentes da arquitetura Document-View, a classe view, que est intimamente relacionada com a janela. Por hora os outros trs componentes bsicos da estrutura de um programa com a MFC no sero abordados. Isto ser feito de forma prtica demonstrando a utilizao do AppWizard para criar um esqueleto de um programa Windows. claro que estes exemplos desse captulo no sero capazes de armazenar dados no disco e no suportaro mltiplas janelas, suportes estes que sero abordados nos prximos captulos. Como os recursos so uma parte importante de um programa para Windows, ser abordada uma introduo do uso da ResourceView, para visualizar e explorar o programa. Sero informadas ainda dicas de como melhorar o tempo de compilao e melhorar a velocidade de execuo de ser programa.
2 SDI x MDI
Dois tipos de aplicativos distintos so suportados pela MFC: Single Document Interface (SDI) e Multiple Document Interface (MDI). Um aplicativo SDI, do ponto de vista do usurio apenas uma janela. Se este aplicativo depende de um arquivo em disco document, 1999-2001 Bernardi, A. Captulo 2
36
apenas um ser suportado por este tipo de aplicativo. Exemplo NotePad. Um aplicativo MDI, suporta mltiplas janelas filhas, cada uma associada a um documento correspondente. Exemplo Word. Quando o AppWizard executado, o tipo MDI o padro sugerido. Certifique-se de mudar essa opo para criar os primeiros exemplos. O tipo MDI ser abordado mais tarde.
3 Exemplo Curso1a
Nesta seo ser abordado um exemplo completo de esqueleto de programa, bem como os passos necessrios para sua criao utilizando o AppWizard. Este exemplo apenas uma janela vazia com um menu e uma barra de ferramentas acoplada. Quando voc criar o primeiro programa executvel MFC , voc usar o MFC AppWizard (verso de EXE) que o conduzir por uma srie de caixas de dilogo nas quais voc escolhe opes para a arquitetura, caractersticas, e funes de seu projeto. A srie um caminho ramificado: voc pode avanar pelos passos e pode fazer mudanas s opes que voc selecionou. Ajuda est disponvel para toda opo no MFC AppWizard: click o boto direito do mouse no controle para mais informao sobre cada opo. Passos para criar um programa MFC EXE usando a ferramenta AppWizard: 1. No menu File, click New e ento clique na pasta de Projects. 2. Especifique o Nome de Projeto, Localizao, Workspace, Dependncia, e opes de Plataformas e ento click duas vezes no cone MFC AppWizard (exe). 3. Complete os passos do MFC AppWizard escolhendo as opes apropriadas para seu programa. 4. Prepare seu programa MFC para uso. (Criar o executvel)
1999-2001 Bernardi, A.
Captulo 2
37
Passo 2 ( para programas SDI ou MDI ) 1- Escolha uma das quatro opes de apoio de banco de dados para seu programa: None, Header file support, Database View (with file support) ou Database View (without file support). 1999-2001 Bernardi, A. Captulo 2
38
2- Se voc selecionou Database View support, click Data Source e escolha qualquer uma base de dados externa via ODBC ou um banco de dados DAO com o arquivo apropriado e uma tabela a ser utilizada. 3- Click Next.
NOTA: Para o exemplo Curso1, no selecione nenhum suporte a banco de dados, simplesmente aceite o padro.
Passo 3 ( para programas SDI ou MDI ) 1- Escolha a combinao de apoio de documento que voc gostaria de incluir em seu programa e ento click Next. Selecionando estas opes habilita-se os recursos de ActiveX e adiciona Automatizao extra comanda ao menu da aplicao. 2- Click Next.
1999-2001 Bernardi, A.
Captulo 2
39
NOTA:
Para
apoio a documento,
Passo 4 ( para programas SDI ou MDI ) 1- Escolha qual interface bsica dos usurios caracteriza o que voc quer para seu programa e o que WOSA apoiam para incluir. Veja Windows Sockets em MFC e MAPI Support em MFC para mais informaes. 2- Se voc quer modificar os nomes de arquivos e extenses que seu programa usar ou quer ajustar a estrutura da janela de interface com usurio para seu programa, click Advanced. 3- Click Next.
1999-2001 Bernardi, A.
Captulo 2
40
Passo 6 ( para programas SDI ou MDI ) 1- Se voc quer mudar o nome de classe padro, classe base, header ou nomes de arquivo de implementao providos pelo AppWizard, entre nos nomes novos. Para mudar a classe Base, selecione o classe View de seu programa. 2- Click Finish.
1999-2001 Bernardi, A.
Captulo 2
41
Passo 7
O AppWizard exibe uma tela com as informaes sobre o programa que est acabando de ser criado.
1999-2001 Bernardi, A.
Captulo 2
42
Quando o boto Ok do dilogo da figura acima for pressionado, o AppWizard comea a criar o cdigo fonte de seu novo projeto. Quando o AppWizard finalizar, visualize o subdiretrio criado para o projeto. Os seguintes arquivos so de interesse por enquanto:
Descrio Arquivo de projeto que permite ao Developer Studio construir seu aplicativo Arquivo de WorkSpace que contm um entrada para o projeto. Arquivo script ASCII de recursos Arquivo de implementao da classe View, que contm as funes membro da classe CCurso1View. Arquivo de definio da classe View, que contm a descrio da classe CCurso1View Arquivo binrio que informa ao Developer Studio que arquivos foram abertos para o projeto e como suas janelas esto arranjadas. Arquivo texto que explica o propsito dos arquivos gerados. Arquivo de cabealho que contm as constantes #define dos identificadores usados pelos recursos.
A Figura 12 mostra a janela FileView do Workspace. Utilize esta janela para localizar os arquivos que compe o projeto atual.
1999-2001 Bernardi, A.
Captulo 2
43
1999-2001 Bernardi, A.
Captulo 2
44
45
A seguir esto os passos que devem ser seguidos para efetuar a operao de alterao do contedo de exibio de uma janela.
void CCurso1aView::OnDraw(CDC* pDC) { CCurso1aDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here }
imprime no canto superior esquerdo com a fonte e tamanho padro seleciona um preenchimento para o interior do circulo desenha um circulo cinza com dimetro de 100 unidades
A chamada da funo GetDocument pode ser seguramente retirada pois ainda no estamos trabalhando com documentos nesse programa. As funes TextOut, SelectStockObject, Ellipse so membros da classe de contexto de dispositivo da Application Framework, CDC. A funo Ellipse desenha um circulo se o retngulo que o limitar possuir dimenses iguais. A MFC prov uma classe de til para trabalhar com retngulos no Windows, CRect. Um objeto temporrio de CRect utilizado como parmetro da funo Ellipse para definir a regio onde ela ser desenhada. Mais adiante voltaremos a entrar em mais detalhes sobre a classe CRect. Passo 2: Recompilar e Testar Curso1a No menu Build selecione a opo Build Curso1a.exe , se nenhum erro ocorrer teste o aplicativo novamente. Agora voc possui um programa que visivelmente faz alguma coisa.
46
arquivo texto, porm modific-lo com um edito de textos no uma boa idia, pois este o trabalho do Editor de Recursos.
#include resource.h
que define trs constantes para o aplicativo atravs das diretivas #define, que so: IDR_MAINFRAME, IDR_CURSO1TYPE e IDD_ABOUTBOX . O editor de recursos deve ser utilizado para se inserir novas constantes nesse arquivo, uma vez que se edit-lo manualmente, na prxima utilizao do Editor de Recursos essas alteraes podem ser descartadas.
1999-2001 Bernardi, A.
Captulo 2
47
Passo 1: Abrir o arquivo RC do aplicativo. Pressione o boto ResourceView na janela Workspace. Se for expandido cada item, a janela de recursos ser como mostrada abaixo na Figura 13:
Passo 2: Examine os recursos do aplicativo. Explore cada tipo individual de recursos. Para selecionar um recursos para edio basta utilizar um double-click sobre ele. Uma janela abrir com a ferramenta necessria para editar aquele tipo de recurso. Se uma caixa de dilogo for aberta para edio a barra de controles aparecer na janela. Passo 3: Modifique o dilogo IDD_ABOUTBOX Faa algumas alteraes na janela do dilogo About, como por exemplo: Altere o tamanho de sua janela arrastando a borda direita ou inferior, movimente o boto Ok de posio, mude o texto, etc. Um click sobre o objeto o seleciona, pressionando o boto direito possvel alterar suas propriedades. Passo 4: Reconstrua o aplicativo, com as modificaes no arquivo de recurso. No menu Build selecione a opo Build Curso1a.exe. O Developer Studio grava as alteraes efetuadas no editor de recursos para o arquivo Curso1a.rc e chama o compilador de recursos para gerar a verso compilada do arquivo de recursos que chamar Curso1a.res que ser linkada ao aplicativo executvel. 1999-2001 Bernardi, A. Captulo 2
48
Passo 5: Teste essa nova verso de aplicativo. Execute o programa Curso1a.exe e escolha a opo About no menu Help, para confirmar que suas alteraes foram feitas no dilogo About.
Abrindo-se o combo na barra de ferramentas Build (Figura 14) encontramos duas opes. Win32 Debug e Win32 Release. Estes itens so alvos que representam opo de construo/compilao diferente. Quando um projeto criado, o AppWizard gera dois alvos (targets) com diferentes opes de compilao/construo que esto resumidos na tabela abaixo:
Release Build
Source Code debugging MFC diagnostic macros Library linkage Compiler optimization
Debug Build
Habilitado Habilitado MFC Debug Library Nenhuma otimizao
Resumindo: voc deve desenvolver seus programas na plataforma Debug e recompila-los na plataforma Release antes de distribu-lo. O Arquivo executvel gerado na plataforma Release menor e mais rpido. Os arquivos de sada e intermedirios so armazenados respectivamente no diretrio Debug e Release, que so criados como sub-diretrios do seu projeto.
49
1999-2001 Bernardi, A.
Captulo 3
50
programa precisa executar uma ao em resposta a esta mensagem ele deve possuir uma funo membro como esta:
Dentro do arquivo de cabealho desta classe deve conter o correspondente prottipo para essa funo:
A notao afx_msg, no gera cdigo, porm o alerta que este prottipo de uma funo mapeada. Portanto, necessrio que haja uma entrada no mapa de mensagens (macro) para fazer a conexo da funo OnLButtonDown com a estrutura das aplicaes.
BEGIN_MESSAGE_MAP(CCurso3AView, CView) ON_WM_LBUTTONDOWN() // entrada especfica para OnLButtonDown // outras entradas ao mapa de mensagens END_MESSAGE_MAP()
DECLARE_MESSAGE_MAP()
Todos estes passos podem ser feitos manualmente, mas o Visual C++ disponibiliza uma ferramenta, o ClassWizard, que automatiza a gerao desses cdigos para a maiioria das mensagens que podem ser mapeadas.
1999-2001 Bernardi, A.
Captulo 3
51
O exemplo dessa seo ir mapear as mensagens para alterar a cor da elipse (estado) toda vez que o mouse for pressionado sobre ela. A inicializao dessas variveis membros deve ser feita no construtor da classe. Dica: Por que no usar uma varivel global para guardar o estado da janela ? Para evitar problemas quando da utilizao de mltiplas janelas, alm de variveis globais furarem o conceito de encapsulamento da programao orientada a objeto. Inicializando os membros de dados da classe View O lugar mais eficiente para se fazer uma inicializao de membros de dados no construtor. Como mostrado no cdigo abaixo.
1999-2001 Bernardi, A.
Captulo 3
52
Visualizando o guia de referncia da MFC (help), fica visvel que estas classes possuem vrios operadores sobrecarregados, que permitem entre outras coisas: Somar ou subtrair objetos CSize a objetos CPoint; Subtrair um objeto CPoint de outro e armazenar em um objeto CSize; Somar ou subtrair objetos CPoint e CSize de objetos CRect. A classe CRect possui ainda outros membros que retornam objetos CPoint e CSize. Neste ponto j podemos perceber que objetos do tipo CSize resultam de uma diferena entre dois objetos CPoint, e que possvel deslocar o canto superior esquerdo de um objeto CRect para coincidir com um objeto CPoint. possvel ainda determinar se um ponto est dentro de um retngulo utilizando a funo membro PtInRect. Por exemplo, para trocar o estado do membro de dados m_nCor pode ser feito um teste para determinar se o mouse est sendo pressionado dentro do retngulo que define a elipse. O cdigo que ficaria dentro da funo OnLButtonDown seria assim:
if (m_rectElipse.PtInRect(point)) {// se for verdadeiro o ponto pertence ao retngulo. if (m_nCor == GRAY_BRUSH) m_nCor = WHITE_BRUSH; else m_nCor = GRAY_BRUSH; InvalidateRect(m_rectElipse) }
Para determinar se o ponto pertence exatamente a uma regio elptica, necessrio construir um objeto do tipo CRgn que corresponda a uma elipse utilizar um de seus membros PtInRegion. Este seria o cdigo:
CRgn rgn; rgn.CreateEllipticRgnIndirect(m_rectElipse); if (rgn.PtInRegion(point)) {// se for verdadeiro o ponto pertence ao retngulo. if (m_nCor == GRAY_BRUSH) m_nCor = WHITE_BRUSH; else m_nCor = GRAY_BRUSH; InvalidateRect(m_rectElipse) }
A classe CRgn pode tamber ser utilizada para definir uma regio poligonal. 1999-2001 Bernardi, A. Captulo 3
53
Utilizando o AppWizard e ClassWizard em cojunto Os seguintes passos mostram como utilizar o AppWizard em conjunto com o ClassWizard para gerar o exemplo Curso3A:
m_nCor; m_rectElipse;
1999-2001 Bernardi, A.
Captulo 3
54
Se preferir pode digitar o cdigo acima dentro da declarao da classe que est no arquivo Curso3AView.h.
1.6.3 Passo3: Use o ClassWizard para adicionar um mapeamento de mensagens a classe CCurso3AView.
Selecione a opo ClassWizard do menu View do Developer Studio, ou pressione o boto direito dentro da janela com o cdigo fonte. Quando a caixa de dilogo do ClassWizard aparecer, certifique-se que a classe CCurso3AView est selecionada como mostra a figura a seguir. Agora pressione o boto do mouse sobre CCurso3AView no topo do list box Object IDs e role o list box Messages para selecionar a mensagem WM_LBUTTONBOWN, e pressione o boto Add Function. A funo OnLButtonDown aparecer no list box Member Functions.
1999-2001 Bernardi, A.
Captulo 3
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos void CCurso3AView::OnLButtonDown(UINT nFlags, CPoint point) { if (m_rectElipse.PtInRect(point)) {// se for verdadeiro o ponto pertence ao retngulo. if (m_nCor == GRAY_BRUSH) m_nCor = WHITE_BRUSH; else m_nCor = GRAY_BRUSH; InvalidateRect(m_rectElipse); } }
55
2 Modos de Mapeamento
Os desenhos realizados at agora foram baseados em unidades de pixels, tambm conhecida como Coordenadas do Dispositivo. No exemplo Curso3A, as unidades utilizadas eram pixels devido ao Contexto de Dispositivo estar ajustado para o Modo de Mapeamento Padro, MM_TEXT. A declarao
pDC->Rectangle(CRect(0,0,200,200));
desenha um quadrado de 200 por 200 pixels, coincidente com o canto superior esquerdo da rea cliente. Notar que se a resoluo do monitor for alterada, para por exemplo 1024x768,
1999-2001 Bernardi, A.
Captulo 3
56
este mesmo quadrado reduzir de tamanho. Se for utilizado um contexto de Impresso (600dpi) este quadrado aparecer com um tamanho bem pequeno. E se meu programa tivesse que desenhar um quadrado de 4x4 cm, independente do dispositivo que esle estivesse sendo mostrado? O Windows possui outros modos de mapeamento, ou sistema de coordenadas, que podem ser associados a um contexto de dispositivo. As coordenadas no modo atual de mapeamento so chamadas Coordenadas Lgicas. Pode parecer fcil manipular estes sistemas de coordenadas, porm no possvel trabalhar apenas em coordenadas lgicas. O programa ter que chavear entre coordenadas lgicas e coordenadas do dispositivo, e voc precisar conhecer quando convert-las.
1999-2001 Bernardi, A.
Captulo 3
57
MM_HIMETRIC MM_TWIPS
0,01 mm 1/1440 in
Obs: O modo MM_TWIPS ser utilizado preferencialmente em contexto de impresso. A unidade twip se refere a 1/20 pontos. Um ponto uma unidade de medida que no windows corresponde exatamente a 1/72 in. Para desenhar um caractere de tamanho 12 pontos (fonte tamanho 12), ajuste a altura do caractere para 12*20, ou 240 twips.
void CMyView::OnDraw(CDC* pDC) { CRect rectCliente; GetClientRect(rectCliente); pDC->SetMapMode(MM_ANISOTROPIC); pDC->SetWindowExt( 1000,1000 ); pDC->SetViewPortExt(rectCliente.right, rectCliente.bottom); pDC->SetViewPortOrg(rectCliente.right/2, rectCliente.bottom/2); pDC->Ellipse(CRect(-500,-500,500,500)); }
No cdigo acima, as funes SetWindowExt e SetViewportExt, trabalham juntas para definir a escala baseada no tamanho da rea cliente retornada pela funo GetClientRect. O resultado que sempre o tamanho da janela conter 1000x1000 unidades lgicas. A funo SetViewportOrg posiciona a origem do sistema de coordenadas para o dentro da janela. Finalmente uma elipse de raio 500 unidades lgicas preenche exatamente a janela. Aqui esto as frmulas para converter as unidades lgicas para unidades de dispositivo: Fator de escala x = extenso x do viewport / extenso x da janela Fator de escala y = extenso y do viewport / extenso y da janela x do dispositivo = x lgico * Fator de escala x + deslocamento da origem em x y do dispositivo = y lgico * Fator de escala y + deslocamento da origem em y
1999-2001 Bernardi, A.
Captulo 3
58
Substituindo-se MM_ANISOTROPIC e MM_ISOTROPIC, a elipse sempre ser vista como um crculo, que se expande e ajusta as menores dimenses do retngulo da rea cliente.
1999-2001 Bernardi, A.
Captulo 3
59
O cdigo a seguir serve para testar se boto esquerdo do mouse foi pressionado dentro de um retngulo:
//assumir que m_rect um membro do tipo CRect de uma classe derivada de //CView utilizando-se do modo de mapeamento de coordenadas lgicas //MM_LOENGLISH . void CMyView::OnLButtonDown(UINT nFlags, CPoint point) { CRect rect = m_rect; // faz uma cpia temporria do objeto m_rect CClientDC dc(this); // isto como se deve pegar um contexto de // dispositivo para o uso das funes // SetMapMode e LPtoDP. dc.SetMapMode(MM_LOENGLISH); dc.LPtoDP(rect); // rect ficou em coordenadas do dispositivo if (rect. PtInRect(point)) TRACE(cursor do mouse est dentro do retngulo); }
O melhor lugar para selecionar o modo de mapeamento dentro da funo virtual OnPrepareDC membro da classe CView, ao invs de fazer isso na OnDraw.
A estrutura das aplicaes chama a funo virtual OnPrepareDC antes de chamar a OnDraw.
1999-2001 Bernardi, A.
Captulo 3
60
void CCurso3AView::OnLButtonDown(UINT nFlags, CPoint point) { CClientDC dc(this); OnPrepareDC(&dc); CRect rectDevice = m_rectElipse; dc.LPtoDP(rectDevice); if (rectDevice.PtInRect(point)) { // se for verdadeiro o ponto pertence ao retngulo. if (m_nCor == GRAY_BRUSH) m_nCor = WHITE_BRUSH; else m_nCor = GRAY_BRUSH; InvalidateRect(rectDevice) } }
1999-2001 Bernardi, A.
Captulo 3
61
A classe CScrollView suporta as barras de rolagem, porm no suporta o rolamento pelo teclado. Este suporte ser includo tambm nesse exemplo.
1999-2001 Bernardi, A.
Captulo 3
62
1999-2001 Bernardi, A.
Captulo 3
63
m_nCor; m_rectElipse;
Se preferir pode digitar o cdigo acima dentro da declarao da classe que est no arquivo Curso3CView.h.
void CCurso3CView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal(20000, 30000); // 20 por 30 cm CSize sizePage(sizeTotal.cx / 2, sizeTotal.cy / 2); CSize sizeLine(sizeTotal.cx / 50, sizeTotal.cy / 50); SetScrollSizes(MM_HIMETRIC, sizeTotal, sizePage, sizeLine); }
1999-2001 Bernardi, A.
Captulo 3
64
void CCurso3CView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { switch (nChar) { case VK_HOME: OnVScroll(SB_TOP, 0, NULL); OnHScroll(SB_LEFT, 0, NULL); break; case VK_END: OnVScroll(SB_BOTTOM, 0, NULL); OnHScroll(SB_RIGHT, 0, NULL); break; case VK_UP: OnVScroll(SB_LINEUP, 0, NULL); break; case VK_DOWN: OnVScroll(SB_LINEDOWN, 0, NULL); break; case VK_PRIOR: OnVScroll(SB_PAGEUP, 0, NULL); break; case VK_NEXT: OnVScroll(SB_PAGEDOWN, 0, NULL); break; case VK_LEFT: OnHScroll(SB_LINELEFT, 0, NULL); break; case VK_RIGHT: OnHScroll(SB_LINERIGHT, 0, NULL); break; default: break; } }
3.5.5 Passo5:
Edite
cdigo
do
construtor
da
funo
OnDraw
em
Curso3CView.cpp.
O cdigo em destaque a seguir deve substituir o contedo previamente existente:
3.5.6 Passo
Utilize
ClassWizard
para
mapear
mensagem
WM_LBUTTONDOWN.
As seguintes alteraes devem ser feitas na funo gerada pelo ClassWizard:
1999-2001 Bernardi, A.
Captulo 3
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos void CCurso3CView::OnLButtonDown(UINT nFlags, CPoint point) { CClientDC dc(this); OnPrepareDC(&dc); CRect rectDevice = m_rectElipse; dc.LPtoDP(rectDevice); if (rectDevice.PtInRect(point)) { // se for verdadeiro o ponto pertence ao retngulo. if (m_nCor == GRAY_BRUSH) m_nCor = WHITE_BRUSH; else m_nCor = GRAY_BRUSH; InvalidateRect(rectDevice); } }
65
66
A mensagem WM_CREATE Est a primeira mensagem que o Windows envia para uma view. A mensagem WM_CLOSE O Windows envia esta mensagem quando o usurio pressiona o boto fechar a partir do menu do sistema. A mensagem WM_QUERYENDSESSION O Windows envia esta mensagem para todos os aplicativos que esto ativos quando o usurio solicita a sada do Windows. A mensagem WM_DESTROY O Windows envia esta mensagem aps a mensagem WM_CLOSE. Quando o programa recebe esta mensagem ele assume que a janela no est mais visvel. A mensagem WM_NCDESTROY Esta a ultima mensagem que o Windows envia quando uma janela est sendo destruda.
1999-2001 Bernardi, A.
Captulo 3
67
Alguns elementos da GDI j foram vistos em captulos anteriores. Toda vez que um programa desenha na tela ou na impressora est utilizando funes da GDI. A GDI possui funes para desenhar pontos, linhas, retngulos, polgonos, elipses, bitmaps e textos. O desenho de crculos, quadrados pode ser feito intuitivamente apenas com um breve estudo das funes disponveis, porm a programao para o desenho de textos um pouco mais complicada. Este captulo se destina a fornecer informaes suficientes para iniciar com o uso da GDI efetivamente dentro do ambiente do Visual C++. Ser apresentado como utilizar fontes efetivamente tanto na impressora como na tela.
1999-2001 Bernardi, A.
Captulo 4
68
Se um objeto do tipo CWindowDC for criado, o ponto (0,0) estar se referenciando ao canto superior esquerdo da rea no-cliente da janela. Lembrar que a janela view no possui uma rea no cliente, portanto o contexto CWindowDC mais aplicvel a janelas frames.
void CCurso3BView::OnLButtonDown(UINT nFlags, CPoint point) { CClientDC dc(this); // constroi um dc na pilha CRect rectDevice = m_rectElipse; dc.LPtoDP(rectDevice); // converte coordenadas }
Repare que, desta forma o construtor da classe CClientDC recebe um ponteiro para uma janela view. O destrutor da classe CClientDC chamado quando a funo termina (retorna). Outra forma de conseguir um contexto em uma funo mapeada utilizando o membro da classe me CWnd::GetDC, como mostrado no cdigo abaixo. Sempre que este mtodo for utilizado deve-se chamar a funo ReleaseDC para destruir o contexto de dispositivo criado.
void CCurso3BView::OnLButtonDown(UINT nFlags, CPoint point) { CDC* pDC = GetDC(); // ponteiro para contexto interno CRect rectDevice = m_rectElipse; pDC->LPtoDP(rectDevice); // converte coordenadas ReleaseDC(pDC); // no deve ser esquecido. }
NOTA: um contexto criado para ser enviado como parmetro para a funo OnDraw no deve ser destruido, a estrutura das aplicaes se encarregar disso.
1999-2001 Bernardi, A.
Captulo 4
69
2 Objetos da GDI.
Objetos da GDI, so representados por uma classe da MFC. CGdiObject uma classe base abstrata para encapsular os objetos da GDI, que so representados dentro do Visual C++ por classes derivadas desta. As seguintes classes so suportadas pelo Visual C++: CBitmap CBrush CFont CPalette CPen CRgn
70
CPen, CBrush permitem que sejam especificados todos os parmetros para a sua criao de uma s vez. Outros como os das classes CFont e CRgn, necessitam de um segundo passo para processar a criao. Para estas classes, o construtor padro deve ser utilizado e em seguida um outra funo membro de inicializao como por exemplo CreateFont ou CreatePolygonRgn devem ser chamadas para completar a criao do objeto. A classe CGdiObject possui um destrutor virtual. Cada classe derivada deve se encarregar de destruir os objetos de seu tipo. A destruio de um objeto da GDI deve ser feita aps o mesmo no esta mais fixado a nenhum contexto de dispositivo. NOTA: no deletar um objeto da GDI era um falha grave dentro do win16, pois o mesmo permanecia alocado at o encerramento do Windows. Com o Win32 os programas possuem sua prpria memria da GDI que desalocada toda vez que o programa for terminado. Porm no cuidar de deletar os objetos da GDI podem causar uma grande perda de memria durante o uso de seu programa principalmente se o objeto for do tipo CBitmap. Agora que j foi discutido a importncia de deletar um objeto da GDI, pode-se falar em como desconectar desses objetos de um contexto de dispositivo. Os membro da classe CDC::SelectObject, constituem uma famlia de funes que se encarregam de selecionar o tipo apropriado ao contexto e retornam um ponteiro para o objeto do mesmo tipo anteriormente selecionado. O problema consiste de que no possvel desselecionar um objeto sem selecionar outro. Isto pode ser resolvido da seguinte forma. O objeto anteriormente selecionado que retorna com a funo SelectObject deve ser guardado quando um objeto criado selecionado. Este objeto guardado deve ser restaurado a GDI quando no mais for utilizado o objeto criado. O trecho abaixo exemplifica como deve ser procedido para utilizar objetos GDI com eficincia:
CMyView::OnDraw(CDC* pDC) { CPen pena(PS_DASHDOTDOT, 2, (COLORREF) 0); //pena preta, tamanho2, // estilo ponto trao CPen* pOldPen = pDC->SelectObject(&pena); pDC->MoveTo( 10, 10 ); pDC->LineTo(110, 10 ); pDC->SelectObject(pOldPen); // pena desselecionada
Quando um contexto destrudo, todos objetos da GDI que estavam fixados a ele so desselecionados.
1999-2001 Bernardi, A.
Captulo 4
71
CMyView::OnDraw(CDC* pDC) { CPen pena(PS_DASHDOTDOT, 2, (COLORREF) 0); //pena preta, tamanho2, // estilo ponto trao pDC->SelectObject(&pena); pDC->MoveTo( 10, 10 ); pDC->LineTo(110, 10 ); pDC->SelectStockObject(BLACK_PEN); // pena desselecionada
1999-2001 Bernardi, A.
Captulo 4
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos m_pFonteImpressao->CreateFont(30,10,0,0, 400, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFALUT_PRECIS, DEFAULT_QUALIT, DEFAULT_PITCH | FF_MODERN, Courier New); // fonte True Type CFont* pOldFont = pDC->SelectObject(m_pFonteImpressao); m_hOldFont = (HFONT) pOldFont->GetSafeHandle(); } void CMyView::TrocaParaOriginal(CDC* pDC) { if (m_hOldFont) pDC->SelectObject(CFont::FromHandle(m_hOldFont); }
72
3 Cores no Windows.
A GDI proporciona uma independncia do hardware utilizado para exibir as cores. Os programas trabalham com cores absolutas e a GDI se encarrega de fazer as combinaes necessrias para que essas cores fiquem visveis no Windows. Atualmente o Windows suporta 4 tipos de modalidades de cores que so processadas pelas respectivas placas de vdeo.
CBrush brush(RGB(0,0,255));
As funes membros da classes CDC, SetBkColor e SetTextColor podem ser utilizadas para trocar a cor de fundo de um texto e trocar a cor das letras respectivamente. Neste modo de vdeo no possvel exibir cores compostas para fontes, a cor slida mais prxima ser mostrada. A tabela a seguir mostra alguns exemplos de cores slidas que podem ser utilizadas neste modo.
1999-2001 Bernardi, A.
Captulo 4
73
Vermelho (R) 0 0 0 255 0 255 255 255 0 0 0 128 128 128 128 192
Verde (G) 0 0 255 0 255 0 255 255 0 128 128 0 0 128 128 192
Azul (B) 0 255 0 0 255 255 0 255 128 0 128 0 128 0 128 192
Cor Preto Azul Verde Vermelho Turquesa Rosa Amarelo Branco Azul escuro Verde escuro Turquesa escuro Vermelho escuro Rosa escuro Amarelo escuro Cinza escuro Cinza claro
1999-2001 Bernardi, A.
Captulo 4
74
mdia 236 nveis de verde, devido a isso esse modo de cores tambm chamado de True Colors)
4 Fontes.
Nos programas anteriores, quando um texto era exibido na tela ele utilizava a fonte System, do Windows. Como comum a todos, o Windows suporta mltiplas fontes, independentes do dispositivo e com tamanhos variveis. Fontes True-Type, so mais fceis de ser manipuladas dentro dos programas do que as fontes que eram dependentes de dispositivos (ex. uma fonte para impressora e outra para a tela). Aps esta introduo terica sobre as fontes sero apresentados exemplos ao final deste captulo.
1999-2001 Bernardi, A.
Captulo 4
75
que para uma fonte de tamanho 8,5 pontos a altura do caractere deve ser especificada por 8,5 x 20, ou 170 twips.
Descrio Largura fsica em milmetros Altura fsica em milmetros Largura em pixels Altura em pixels Pontos por polegadas lgicas na horizontal Pontos por polegadas lgicas na vertical
Os ndices HORZSIZE e VERTSIZE representam as dimenses fsicas do monitor. (esses indices podem no corresponder com a realidade pois o Windows no sabe exatamente o tamanho do monitor que est acoplado a placa de vdeo). O tamanho da tela pode ser calculada multiplicando-se HORZRES e VERTRES por LOGPIXELSX e LOGPIXELSY respectivamente. Um modo de mapeamento utilizado pelo Word, chamado de logical twips, onde cada unidade lgica corresponde exatamente a 1/1440 polegadas lgicas. Este modo de mapeamento independente do sistema operacional e da resoluo do display. Para setar este modo pode utilizar o seguinte cdigo
pDC->SetMapMode(MM_ANISOTROPIC); pDC->SetWindowEst(1440,1440); pDC->SetViewportExt(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY) );
1999-2001 Bernardi, A.
Captulo 4
76
5 Exemplo Curso4A
1999-2001 Bernardi, A.
Captulo 4
77
5.2 Utilize o ClassWizard para sobrecarregar a funo virtual OnPrepareDC da classe view
Edite o cdigo no arquivo Curso4AView.cpp deixando-o como o a seguir:
void CCurso4AView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { pDC->SetMapMode(MM_ANISOTROPIC); pDC->SetWindowExt(1440, 1440); pDC->SetViewportExt(pDC->GetDeviceCaps(LOGPIXELSX), -pDC->GetDeviceCaps(LOGPIXELSY)); }
void CCurso4AView::ExibirFonte(CDC* pDC, int& nPos, int nPoints) { TEXTMETRIC tm; CFont fontText; CString strText; CSize sizeText; fontText.CreateFont(-nPoints * 20, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial"); CFont* pOldFont = (CFont*) pDC->SelectObject(&fontText); pDC->GetTextMetrics(&tm); TRACE("pontos = %d, tmHeight = %d, tmInternalLeading = %d," " tmExternalLeading = %d\n", nPoints, tm.tmHeight, tm.tmInternalLeading, tm.tmExternalLeading); strText.Format("Esta uma fonte Arial de %d-pontos", nPoints); sizeText = pDC->GetTextExtent(strText); TRACE("largura da string = %d, altura da string = %d\n", sizeText.cx, sizeText.cy); pDC->TextOut(0, nPos, strText); pDC->SelectObject(pOldFont); nPos -= tm.tmHeight + tm.tmExternalLeading; }
1999-2001 Bernardi, A.
Captulo 4
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos for (int i = 6; i <= 24; i += 2) { ExibirFonte(pDC, nPosition, i); } TRACE("LOGPIXELSX = %d, LOGPIXELSY = %d\n", pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY)); TRACE("HORZSIZE = %d, VERTSIZE = %d\n", pDC->GetDeviceCaps(HORZSIZE), pDC->GetDeviceCaps(VERTSIZE)); TRACE("HORZRES = %d, VERTRES = %d\n", pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES)); }
78
pontos = 6, tmHeight = 150, tmInternalLeading = 30, tmExternalLeading = 0 largura da string = 1725, altura da string = 150 pontos = 8, tmHeight = 210, tmInternalLeading = 45, tmExternalLeading = 0 largura da string = 2505, altura da string = 210 pontos = 10, tmHeight = 240, tmInternalLeading = 45, tmExternalLeading = 0 largura da string = 3120, altura da string = 240 pontos = 12, tmHeight = 270, tmInternalLeading = 30, tmExternalLeading = 15 largura da string = 3735, altura da string = 270 pontos = 14, tmHeight = 330, tmInternalLeading = 45, tmExternalLeading = 15 largura da string = 4545, altura da string = 330 pontos = 16, tmHeight = 360, tmInternalLeading = 45, tmExternalLeading = 15 largura da string = 5025, altura da string = 360 pontos = 18, tmHeight = 405, tmInternalLeading = 45, tmExternalLeading = 15 largura da string = 5775, altura da string = 405 pontos = 20, tmHeight = 480, tmInternalLeading = 75, tmExternalLeading = 15
1999-2001 Bernardi, A.
Captulo 4
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos largura da string = 6525, altura da string = 480 pontos = 22, tmHeight = 495, tmInternalLeading = 60, tmExternalLeading = 15 largura da string = 6945, altura da string = 495 pontos = 24, tmHeight = 540, tmInternalLeading = 60, tmExternalLeading = 15 largura da string = 7575, altura da string = 540 LOGPIXELSX = 96, LOGPIXELSY = 96 HORZSIZE = 211, VERTSIZE = 158 HORZRES = 800, VERTRES = 600
79
6 Exemplo Curso4B
Este exemplo similar ao anterior porm possui duas diferenas bsicas:
1999-2001 Bernardi, A.
Captulo 4
80
1. Utiliza
com
uma escala
dependente do tamanho da janela. 2. Exibe mltiplas fontes na mesma tela Os seguintes passos deve ser seguidos para a criao desse exemplo:
6.2 Passo2: Utilize o ClassWizard para sobrecarregar a funo OnPrepareDC da classe CCurso5BView.
Edite o cdigo no arquivo Curso4BView.cpp e torne-o como o a seguir:
void CCurso4BView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { CRect clientRect; GetClientRect(clientRect); pDC->SetMapMode(MM_ANISOTROPIC); // +y = down pDC->SetWindowExt(400,450); pDC->SetViewportExt(clientRect.right, clientRect.bottom); pDC->SetViewportOrg(0, 0); }
1999-2001 Bernardi, A.
Captulo 4
81
6.4 Passo4: Editar a funo membro OnDraw para deix-la como no cdigo abaixo:
Torne o cdigo da funo OnDraw como o a seguir:
void CCurso4BView::OnDraw(CDC* pDC) { CFont fontTest1, fontTest2, fontTest3, fontTest4; fontTest1.CreateFont(50, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial"); CFont* pOldFont = pDC->SelectObject(&fontTest1); TraceMetrics(pDC); pDC->TextOut(0, 0, "This is Arial, default width"); fontTest2.CreateFont(50, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_MODERN, "Courier"); // not TrueType pDC->SelectObject(&fontTest2); TraceMetrics(pDC); pDC->TextOut(0, 100, "This is Courier, default width"); fontTest3.CreateFont(50, 10, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN, NULL); pDC->SelectObject(&fontTest3); TraceMetrics(pDC); pDC->TextOut(0, 200, "This is generic Roman, variable width"); fontTest4.CreateFont(50, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_MODERN, "LinePrinter"); pDC->SelectObject(&fontTest4); TraceMetrics(pDC); pDC->TextOut(0, 300, "This is LinePrinter, default width"); pDC->SelectObject(pOldFont); }
1999-2001 Bernardi, A.
Captulo 4
82
1999-2001 Bernardi, A.
Captulo 4
83
7 Exemplo Curso4C
No exemplo Curso3C, foi inciado a utilizao da classe CScrollView. Neste exemplo ser mostrado como proceder para mover um elipse com o mouse, utilizando uma janela rolvel com o modo de mapeamento MM_LOENGLISH. A rolagem pelo teclado foi deixada de fora, porm se desejvel, basta utilizar os passos descritos no exemplo Curso3C para criar a funo OnKeyDown semelhante. Em vez de utilizar um brush do estoque, ser utilizado um brush hachurado para o preenchimento da elipse. S h uma restrio para o uso de brushes hachurados, a origem da janela rolante deve ser resetada, caso contrrio o efeito de preenchimento pode parecer esquisito. Como no programa Curso3C, este exemplo utiliza uma classe View derivada de CScrollView. (No esquea de mudar isso no passo 6 do AppWizard) aqui esto os passos para criar este aplicativo:
1999-2001 Bernardi, A.
Captulo 4
84
protected: const CSize m_sizeElipse; // logical CPoint m_pointTopLeft; // logical, canto superior esquerdo do // retangulo que define a elipse CSize m_sizeOffset; // dispositivo, do canto superior esquerdo // at o ponto de captura BOOL m_bCaptured; // flag que indica estado da captura do mouse
1999-2001 Bernardi, A.
Captulo 4
85
7.4 Passo4: Editar as funes que acabaram de ser mapeadas tornando-as como as da listagem abaixo.
O ClassWizard gera o esqueleto das funes que foram mapeadas no passo anterior, encontre-as no arquivo de implementao curso4CView.cpp e codifique-as como a seguir:
void CCurso4CView::OnLButtonDown(UINT nFlags, CPoint point) { CRect rectEllipse(m_pointTopLeft, m_sizeElipse); // ainda logicas CRgn circle; CClientDC dc(this); OnPrepareDC(&dc); dc.LPtoDP(rectEllipse); // Agora em coordenadas do dispositivo circle.CreateEllipticRgnIndirect(rectEllipse); if (circle.PtInRegion(point)) { // Capturando o mouse at a prxima mensagem LButtonUp SetCapture(); m_bCaptured = TRUE; CPoint pointTopLeft(m_pointTopLeft); dc.LPtoDP(&pointTopLeft); m_sizeOffset = point - pointTopLeft; //coordenadas do dispositivo // Novo cursor enquanto o mouse estivar capturado ::SetCursor(::LoadCursor(NULL, IDC_CROSS)); } } void CCurso4CView::OnLButtonUp(UINT nFlags, CPoint point) { if (m_bCaptured) { ::ReleaseCapture(); m_bCaptured = FALSE; } } void CCurso4CView::OnMouseMove(UINT nFlags, CPoint point) { if (m_bCaptured) { CClientDC dc(this); OnPrepareDC(&dc); CRect rectOld(m_pointTopLeft, m_sizeElipse); dc.LPtoDP(rectOld); InvalidateRect(rectOld, TRUE); m_pointTopLeft = point - m_sizeOffset; dc.DPtoLP(&m_pointTopLeft); CRect rectNew(m_pointTopLeft, m_sizeElipse); dc.LPtoDP(rectNew); InvalidateRect(rectNew, TRUE); } }
7.5 Passo5: Editar o construtor da classe CCurso4CView, a funo membro OnDraw e a funo membro OnInitialUpdate
O AppWizard gera o esqueleto dessas funes, encontre-as no arquivo de implementao curso4CView.cpp e codifique-as como a seguir:
1999-2001 Bernardi, A.
Captulo 4
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos CCurso4CView::CCurso4CView() : m_sizeElipse(100, -100), m_pointTopLeft(0, 0), m_sizeOffset(0, 0) { m_bCaptured = FALSE; } void CCurso4CView::OnDraw(CDC* pDC) { CBrush brushHatch(HS_DIAGCROSS, RGB(255, 0, 0)); CPoint point(0, 0); // logical (0, 0) pDC->LPtoDP(&point); pDC->SetBrushOrg(point); // Em coordenadas do dispositivo, // Alinhar o brush com a origem // da janela pDC->SelectObject(&brushHatch); // Seleciona Brush pDC->Ellipse(CRect(m_pointTopLeft, m_sizeElipse)); pDC->SelectStockObject(BLACK_BRUSH); // Desseleciona brushHatch // Testa retangulo invalido pDC->Rectangle(CRect(100, -100, 200, -200)); } void CCurso4CView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal(800, 1050); // 8-por-10.5 polegadas CSize sizePage(sizeTotal.cx / 2, sizeTotal.cy / 2); CSize sizeLine(sizeTotal.cx / 50, sizeTotal.cy / 50); SetScrollSizes(MM_LOENGLISH, sizeTotal, sizePage, sizeLine); }
86
1999-2001 Bernardi, A.
Captulo 4
87
7.7 Elementos importantes desse programa. 7.7.1 As variveis membros m_sizeElipse e m_pointTopLeft
Ao invs de armzenar o retngulo que define a elipse em uma varivel do tipo CRect, este exemplo o faz de forma separada, armazena o tamanho (m_sizeElipse) e a posio do canto superior esquerdo (m_pointTopLeft). Para mover esta elipse o programa simplesmente calcula a nova posio do canto superior esquerdo, eliminando com isso quanquer erro de arrefondamento que possa ocorrer no tamanho da elipse.
88
A funo LoadCursor possui dois parmetros, quando o primeiro NULL, indica que um recurso cursor padro do Windows est sendo requisitado. Este recurso ativado pela funo SetCursor e permanece ativo enquanto o mouse estiver capturado.
1999-2001 Bernardi, A.
Captulo 4
89
Quase todos os programas para o Windows possuem janelas dilogo para interagir com o usurio. Um dilogo pode ser desde um simples Message Box com um boto OK at um formulrio complexo para entrada de dados. Esses dilogos so elementos que se comportam como uma verdadeira janela, recebem mensagens, podem ser movidos e fechados, alm de aceitar elementos de desenho vistos anteriormente em seu interior. H dois tipos de dilogos, Modal e Modeless. Estaremos abordando o tipo mais comum que o dilogo modal. Ainda neste captulo sero implementados exemplos de interao com dilogos atravs de controles do Windows.
2 Recursos e controles
Agora que voc j sabe que um dilogo uma janela, o que o torna diferente de uma janela CView ser visto nessa seo. Dilogos sempre fazem parte dos recursos de um programa Windows que conter seu identificador e o layout de como esse dilogo se
1999-2001 Bernardi, A.
Captulo 5
90
apresentar na tela. O editor de recursos poder ser utilizado para construir o layout desses dilogos de forma amigvel e completamente visual. Um dilogo pode conter muitos elementos em seu interior. Esses elementos recebem o nome de Controles. Fazem parte desses controles, as caixas de texto (edit box), botes, list box, caixas de seleo (combo box), textos estticos(labels), entre outros. Esses controles podem ser referenciados dentro do programa por ponteiros para CWnd, bem como pelo uso de identificadores associados aos recursos, que o meio mais comum. O controle envia uma mensagem ao dilogo em resposta a uma interao com o usurio como por exemplo o pressionamento de um boto. A MFC e o ClassWizard trabalham juntos para facilitar o uso de dilogos dentro de um programa Windows. O ClassWizard cria uma classe derivada de CDialog para cada dialogo e permite ainda que sejam associadas variveis membros a controles do dilogo. Podem ser especificados os limites de nmeros e tamanho de strings para as variveis membros criadas, que o ClassWizard se encarrega criar as chamas a data validation e data exchange que faro o controle de troca entre os dados que constam na caixa de dilogo e as variveis membros.
91
CMyDialog:: CMyDialog(CWnd* pParent /*NULL*/ ) : CDialog (CMyDialog::IDD, pParent) { // initialization code here }
Caso o identificador que represente seu dilogo tenha que ser alterado, no se esquea de alterar o valor do novo identificador dentro da descrio da classe.
3. Utilize o ClassWizard para adicionar os membros de dados do dilogo bem como suas funes de exchange e validao. 4. Utilize o ClassWizard para mapear as mensagens cos controles para funes membros da nova classe. 5. Escreva o cdigo necessrio para inicializaes especiais dos controles (em OnInitDialog) e os cdigos necessrios ao processamento das mensagens. 6. Escreva o cdigo necessrio a chamada do dilogo dentro de sua classe vies. Este cdigo corresponde a uma chamada a funo membros da classe CDialog, DoModal. O retorno dessa funo s feito aps o usurio fechar a caixa de dilogo.
A seguir encontra-se um exemplo real passo a passo para a criao de um dilogo em um programa baseado em Windows.
4 Exemplo Curso5A
O dilogo criado para o exemplo Curso5A.exe, no apenas uma caixa de dilogo e sim um enorme dilogo que inclui um controle de cada tipo. Essa tarefa se torna mais fcil utilizando o editor de dilogos do Developer Studio. O resultado final est mostrado na Figura 25.
1999-2001 Bernardi, A.
Captulo 5
92
1999-2001 Bernardi, A.
Captulo 5
93
Na tela do Developer Studio ser exibido o novo dilogo que acabou de ser criado como mostrado na Figura 28.
O identificador IDD_DIALOG1 foi associado a esse recurso. Note tambm que o dilogo j possui um boto Ok e Cancel.
1999-2001 Bernardi, A.
Captulo 5
94
Obs: para mater a janela de propriedades sempre visvel, fixe-a utilizando o boto existente em seu canto superior esquerdo.
1999-2001 Bernardi, A.
Captulo 5
95
A seguir encontra-se uma breve descrio de cada um dos controles que sero adicionados ao novo dilogo. Controle Texto esttico para o campo Nome. Um controle texto esttico, simplesmente coloca caracteres na tela. Nenhuma interao com o usurio ocorre neste tipo de controle. O texto que ser exibido nesse controle pode ser alterado na caixa de edio Capition das propriedades desse controle. Para inserir um texto esttico no dilogo basta selecionar o boto apropriado na barra de controle 1999-2001 Bernardi, A. Captulo 5
96
e definir sua posio e tamanho dentro do dilogo utilizando o mouse. Nenhum outro controle esttico ser descrito adiante pois todos so iguais para o dilogo, possuem o mesmo ID e so adicionados da mesma forma, o que no causa problema ao programa pois ele no ter que acessar nenhum deles. Controle Edit Box para o Nome. Um edit control a meio mais fcil de se entrar com um texto dentro de um dilogo. Pressione o boto direito do mouse sobre esse controle e selecione a opo Properties. Altere o identificador do controle de IDC_EDIT1 para IDC_NOME. Aceite todas as outras opes padres. Controle Edit Box para o RG. Este controle adicionado como o anterior exceto que seu identificador tem que ser alterado para IDC_RG. Mais tarde esse identificador ser utilizado pelo ClassWizard para adicionar um campo numrico. Controle Edit Box para a Bio (biografia). Este um controle que deve possuir mais de uma linha (multiline). Altere seu identificador para IDC_BIO, e selecione suas propriedades como mostrado na Figura 33.
Controle Group Box para a categoria. Este um controle serve apenas para separar visualmente os radio buttons das categorias. Altere seu Capition para Categoria e aceite o identificador padro. Os Radio Buttons para o Horista e Salrio. Posicione estes radio buttons dentro do group box categoria. Altere o identificador do boto Horista para IDC_CAT e selecione as outras propriedades como mostrado na figura abaixo:
1999-2001 Bernardi, A.
Captulo 5
97
Certifique-se que a propriedade Auto est setada (padro) na pasta Styles, e apenas o boto horista est com a propriedade Group setada. Quando estas propriedades esto corretamente configuradas o Windows garante que apenas um estar selecionado ao mesmo tempo. O Group box Categoria no tem nenhum efeito sob a operao desses botes.
Controle Group Box para o Seguro. Este um controle serve apenas para separar visualmente check box dos tipos de seguro contratados. Altere seu Capition para Seguro e aceite o identificador padro. Nota: Mais tarde quando for alterar a ordem de tabulao do dilogo, certifique-se que este controle ser o posterior ao radio button do grupo das categorias. Altere a propriedade desse controle para Group de modo que identifique para o Windows o fim do grupo das categorias. Caso isto no seja feito, varias mensagens de Warning sero exibidas na janela Output quando o programa estiver rodando em modo Debug.
Os check Box para Vida, Invalidez e Sade. Posicione estes controles dentro do Group box Seguro. Aceite todos os estilos padres, porm altere os identificadores para respectivamente, IDC_VIDA, IDC_INVALID, IDC_SAUDE. Controle Combo Box para o Cargo. Este primeiro dos trs tipos de combos existentes. Altere seu identificador para IDC_CARGO, selecione a pasta estilo e escolha o tipo Simple. Click na pasta Data e adicione os tres cargos como mostrado na figura abaixo (Obs: cada final de linha no list box deve ser informado a caixa de propriedades utilizando-se a combinao de teclas Ctrl+Enter). Com o tipo Simple, um texto pode ser informado digitando-se um novo valor bem como selecionado um pr-existente na lista.
1999-2001 Bernardi, A.
Captulo 5
98
Controle Combo Box para o Grau. Altere seu identificador para IDC_GRAU, e aceite todos outros estilos como o padro. Click na pasta Data e adicione os tres nveis de instruo: Primrio, Colegial, Graduao. No estio DropDown, o usurio pode digitar um texto no edit box ou selecion-lo da lista, pressionando-se a seta que aparece no canto direito do controle. Controle List Box para o Departamento. Altere seu identificador para IDC_DEPT, aceite todos outras propriedades como padres. Em um list box o usurio pode selecionar apenas um dos elementos utilizando o mouse, as teclas UP e DOWN ou pressionando o caractere correspondente a primeira letra da opo desejada. Note que utilizando o editor de dilogo no possvel adicionar nenhuma opo inicial a um list box, isto ser visto mais tarde no exemplo. Controle Combo Box para a Lngua. Altere seu identificador para IDC_LANG, selecione a pasta Styles e escolha o tipo DropList. Adicione tres entradas de dados (Ingles, Frances, Espanhol) na pasta Data. Este tipo de combo permite que o usurio apenas selecione um item da lista, no possvel editar um novo valor que no esteja na lista. A seleo pode ser feita utilizando-se o mouse ou o teclado. Controle Barra de Scroll para a Leadade e Confiabilidade. No confunda um controle barra de scroll com uma barra de rolamento de uma janela. So criados e dimensionados em tempo de projeto, no de execuo. Altere seus identificadores para respectivamente IDC_LEALDADE, IDC_CONFIABILIDADE. O Botes Ok, Cancel e Special. Verifique se os Capition dos botes so respectivamente Ok, Cancel e Special. Altere o identificador do boto Special para IDC_SPECIAL. Icone. Qualquer cone ou bitmap pode ser exibido dentro de um dilogo utilizando-se este controle (Picture).
1999-2001 Bernardi, A.
Captulo 5
99
1999-2001 Bernardi, A.
Captulo 5
100
Aceite a opo padro Create a new class, e pressione Ok. Preencha os dados para a nova classe como mostrado na figura a seguir. Coloque o nome da classe que seja relacionado com um dilogo. Por exemplo as ultimas trs letras do nome da classe como Dlg. E pressione Ok.
1999-2001 Bernardi, A.
Captulo 5
101
necessrio associar membros de dados a cada um dos controles do dilogo. Para isto, selecione um identificador correspondente a um controle e pressione o boto Add Variable. O dilogo Add Member Variable ser exibido como mostrado na Figura 41:
1999-2001 Bernardi, A.
Captulo 5
102
Digite o nome da varivel e escolha seu tipo de acordo com a tabela abaixo. Certifique-se que os nomes das varives so exatamente como os mostrados na tabela abaixo, pois maiusculas e minusculas afetam os nomes de variveis em C++. Pressione Ok e repita a operao para todos os outros controles.
ID do controle IDC_BIO IDC_NOME IDC_RG IDC_CARGO IDC_CAT IDC_CONFIABILIDADE IDC_LEALDADE IDC_LANG IDC_SAUDE IDC_VIDA IDC_INVALID IDC_GRAU IDC_DEPT
Membro de dados m_strBio m_strNome m_nRg m_strCargo m_nCat m_nConfiabilidade m_nLealdade m_strLingua m_bSegSaude m_bSegVida m_bSegInvalid m_strGrau m_strDepart
Tipo CString CString int CString int int int CString BOOL BOOL BOOL CString CString
Selecionando as variveis criadas no dilogo do ClassWizard, alguns edit box podem aparecer na parte inferior da janela onde podem ser especificados as restries para aquele tipo de varivel. Por exemplo se uma varivel do tipo CString for selecionada aparecer um edit box onde pode ser especificado o mximo numero de caracteres que pode conter esta string.
1999-2001 Bernardi, A.
Captulo 5
103
Um nome pode ser digitado para a funo, porm o ClassWizard sempre sugere um nome que significativo ao evento e quase sempre ser aceito sem alteraes. Aps pressionar OK, a funo passou a ser mapeada para a classe e o boto Edit Code pode ser usado para a edio do corpo da funo, que dever conter as seguintes inscries:
Obs: outros membros, como por exemplo a funo que responder ao boto ok j esto mapeadas pela classe me CDialog, portanto no necessrio que sejam adicionadas funes para esses membros.
1999-2001 Bernardi, A.
Captulo 5
104
O ClassWizard pode ser utilizado para inserir o manipulador da mensagem WM_INITDIALOG ao cdigo fonte da classe. Para isto selecione CCurso5ADlg no list box Object IDs e realize um duplo clique sobre a mensagem WM_INITDIALOG que aparecer no list box Messages. Utilize o boto Edit Code para deixar a implementao da funo OnInitDialog como mostrada abaixo:
BOOL CCurso5ADlg::OnInitDialog() { CListBox* pLB = (CListBox*) GetDlgItem(IDC_DEPT); pLB->InsertString(-1, "Documentao"); pLB->InsertString(-1, "Contabilidade"); pLB->InsertString(-1, "Recursos Humanos"); pLB->InsertString(-1, "Segurana"); // Chame a funo aps a inicializao return CDialog::OnInitDialog(); }
Uma inicializao para os combo boxes pode ser feita de forma semelhante ao invs de preenche-los no momento de sua criao.
1999-2001 Bernardi, A.
Captulo 5
105
4.3.3 Passo3: Escreva o cdigo fonte para a funo OnLButtonDown no arquivo curso5Adlg.cpp
Adicione o cdigo em destaque abaixo no corpo da funo OnLButtonDown. Uma boa parte do cdigo consiste de funes TRACE que so utilizadas para exibir o contedo do dilogo aps o mesmo ser fechado. A chamada do construtor da classe CCurso5ADlg e a posterior chamada do mtodo DoModal so de especial interesse nesse momento.
void CCurso5AView::OnLButtonDown(UINT nFlags, CPoint point) { CCurso5ADlg dlg; dlg.m_strNome dlg.m_nRg dlg.m_nCat dlg.m_strBio = "de Tal, Fulano"; = 123456789; = 1; // 0 = horista, 1 = salario = "No possui um grau de motivao satisfatrio para trabalhar como programador"; dlg.m_bSegVida = TRUE; dlg.m_bSegInvalid = FALSE; dlg.m_bSegSaude = TRUE; dlg.m_strDepart = "Segurana"; dlg.m_strCargo = "Programador"; dlg.m_strLingua = "Ingls"; dlg.m_strGrau = "Graduao"; dlg.m_nConfiabilidade = dlg.m_nLealdade = 50; int ret = dlg.DoModal(); TRACE("DoModal return = %d\n", ret); TRACE("Nome = %s, RG = %d, Cat = %d\n", dlg.m_strNome, dlg.m_nRg, dlg.m_nCat); TRACE("Dept = %s, Cargo = %s, Lingua = %s, Grau = %s\n", dlg.m_strDepart, dlg.m_strCargo, dlg.m_strLingua, dlg.m_strGrau); TRACE("Vida = %d, Invalid = %d, Saude = %d, bio = %s\n", dlg.m_bSegVida, dlg.m_bSegInvalid, dlg.m_bSegSaude, dlg.m_strBio); TRACE("Confiabilidade = %d, Lealdade = %d\n", dlg.m_nConfiabilidade, dlg.m_nLealdade); }
4.3.4 Passo4: Adicione o cdigo a funo membro virtual OnDraw no arquivo Curso5AView.cpp
Para informar ao usurio que ele deve pressionar o boto esquerdo do mouse sobre a janela o seguinte cdigo deve ser adicionado ao mtodo OnDraw:
1999-2001 Bernardi, A.
Captulo 5
106
// deve ser incluido para a classe do dialogo poder ser reconhecida dentro da view #include "Curso5ADlg.h" //
CDialog::DoModal CCurso5ADlg::OnInitDialog ... inicializaes adicionis... CDialog::OnInitDialog CWnd::UpdateDate(FALSE) CCurso5ADlg::DoDataExchange Usuario entra com dados... Usuario pressiona boto Ok CCurso5ADlg::OnOk ... validaes adicionais... CDialog::OnOk CWnd::UpdateDate(TRUE) CCurso5ADlg::DoDataExchange CDialog::EndDialog(IDOK)
As funes virtuais OnInitDialog e DoDataExchange so sobrecarregadas dentro da classe do dilogo para realizar as tarefas especficas do dilogo. A listagem da funo DoDataExchange est exibida a seguir:
void CCurso5ADlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CCurso5ADlg) DDX_Text(pDX, IDC_BIO, m_strBio); DDX_Radio(pDX, IDC_CAT, m_nCat); DDX_LBString(pDX, IDC_DEPT, m_strDepart); DDX_Check(pDX, IDC_SAUDE, m_bSegSaude);
1999-2001 Bernardi, A.
Captulo 5
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos DDX_Check(pDX, IDC_VIDA, m_bSegVida); DDX_Check(pDX, IDC_INVALID, m_bSegInvalid); DDX_Text(pDX, IDC_NOME, m_strNome); DDX_Text(pDX, IDC_RG, m_nRg); DDX_CBString(pDX, IDC_CARGO, m_strCargo); DDX_Scroll(pDX, IDC_CONFIABILIDADE, m_nConfiabilidade); DDX_Scroll(pDX, IDC_LEALDADE, m_nLealdade); DDX_CBString(pDX, IDC_LANG, m_strLingua); DDX_CBString(pDX, IDC_GRAU, m_strGrau); //}}AFX_DATA_MAP }
107
As funes DoDataExchange, DDX_ e DDV_ so bidirecionais. Se o mtodo UpdateData chamado com o parmetro FALSE, essas funes transferem o contedo das variveis membros para os controles do dilogo. Se o parmetro for TRUE, ocorre o processo inverso, ou seja essas funes transferem o contedo dos controles para as variveis membros. A funo EndDialog critica para o procedimento de sada do dilogo. DoModal retorna o parmetro passado por EndDialog IDOK, para aceitar os dados do dilogo e IDCANCEL para desconsiderar as alteraes feitas no dilogo.
4.5.1 Passo1: Adicione as declaraes de enum para as faixas de scroll de mnimo e mximo.
No arquivo Curso5ADlg.h, adicione as seguintes linhas no incio da descrio da classe.
1999-2001 Bernardi, A.
Captulo 5
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos CScrollBar* pSB = (CScrollBar*) GetDlgItem(IDC_LEALDADE); pSB->SetScrollRange(nMin, nMax); pSB = (CScrollBar*) GetDlgItem(IDC_CONFIABILIDADE); pSB->SetScrollRange(nMin, nMax);
108
4.5.3 Passo3: Utilize o ClassWizard para mapear a funo que manipula as mensagens do Scroll
Escolha a mensagem WM_HSCROLL, e adicione uma funo membro OnHScroll e digite o seguinte cdigo em destaque:
void CCurso5ADlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int nTemp1, nTemp2; nTemp1 = pScrollBar->GetScrollPos(); switch(nSBCode) { case SB_THUMBPOSITION: pScrollBar->SetScrollPos(nPos); break; case SB_LINELEFT: // left arrow button nTemp2 = (nMax - nMin) / 10; if ((nTemp1 - nTemp2) > nMin) { nTemp1 -= nTemp2; } else { nTemp1 = nMin; } pScrollBar->SetScrollPos(nTemp1); break; case SB_LINERIGHT: // right arrow button nTemp2 = (nMax - nMin) / 10; if ((nTemp1 + nTemp2) < nMax) { nTemp1 += nTemp2; } else { nTemp1 = nMax; } pScrollBar->SetScrollPos(nTemp1); break; } }
109
Se for desejvel apenas exibir um texto, o meio mais fcil de se fazer isso seria incluindo um controle do tipo Texto Esttico, sem Capition e com um ID nico (no serve IDC_STATIC) e enviar a mensagem CWnd::SetDlgItemText na funo membro OnInitDialog para adicionar o texto dinamicamente ao dilogo. Exibir grficos uma tarefa um pouco mais complicada. necessrio utilizar o ClassWizard para sobrecarregar a funo OnPaint. Dentro desta funo transformado um controle esttico em um ponteiro para CWnd, o qual possvel extrair seu contexto para poder realizar o desenho. Esta tcnica utilizada para desenhar dentro de um controle prevenindo que o Windows apague seu trabalho mais tarde. As funes Invalidade/UpdateWindow so utilizada para informar que seu controle foi alterado e precisa ser redesenhado. A seguir encontra-se um cdigo para a funo OnPaint que desenhar um retngulo preto no interior de um controle estatico.
void CMyDialog::OnPaint() { CWnd* pWnd = GetDlgItem(IDC_STATIC1); CDC* pControlDC = pWnd->GetDC(); pWnd->Invalidate(); pWnd->UpdateWindow(); pControlDC->SelectStockObject(BLACK_BRUSH); pControlDC->Rectangle(0,0,10,10); pWnd->ReleaseDC(pControlDC); }
1999-2001 Bernardi, A.
Captulo 5
110
Neste captulo ser discutido como os Documentos (doc) mantm os dados do aplicativo e como as vistas (view) apresentam esses dados ao usurio. Alm de aprender como essas classes interagem entre si enquanto o aplicativo est em execuo. Ainda neste captulo sero mostrados dois exemplos que utilizam a classe CFormView como base para suas classes de vista. No primeiro exemplo a classe doc mantm os dados de apenas um objeto do tipo CEstudante que representa um nico registro do tipo estudante e a classe view oferece meios para a alterao desses dados. A classe CEstudante servir como de exemplo para a implementao de classes que representem elementos do mundo real dentro de um programa. O segundo exemplo introduz o conceito de ponteiro para colees, atravs das classes CObList e CTypePtrList. Agora o documento ser capaz de armazenar uma coleo de registros do tipo estudante, e a classe view permitir o acesso individual a cada um desses registros.
1999-2001 Bernardi, A.
Captulo 6
111
Quando o AppWizard cria a classe derivadas de CView, cria uma verso especial da funo GetDocument que retorna no um ponteiro para a classe CDocument mas sim um ponteiro para a classe derivada de CDocument que pertence a seu aplicativo, criando assim um tipo seguro que conhecer todos os dados exclusivos de seu aplicativo.
GetDocument()->UpdateAllViews(this);
O parmetro pSender no nulo, identifica para a estrutura das aplicaes que a view atual no precisa ser notificada e assume que ela j contm os dados atualizados. Isto previne que uma atualizao da view onde os dados foram alterados no seja realizada. Essa funo possui ainda parmetros opcionais hint, que informam a janela como ela dever ser atualizada. O uso desses parmetros dependente do aplicativo e constituem um uso avanado desse tipo de funo. Como a classe view notificada quando a funo UpdateAllViews chamada exatamente o assunto da prxima funo membro a ser discutida, a OnUpdate.
1999-2001 Bernardi, A.
Captulo 6
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos { CMyDocument* pDoc = GetDocument(); CString nome = pDoc->GetNome(); m_pstaticNome->SetWindowText(nome); // m_pstaticNome membro da view }
112
A implementao padro da classe OnUpdate causa um invalidate em toda a rea cliente da janela. Se a funo CDocument::UpdateAllViews chamada com o parmetro pSender contendo um ponteiro para um objeto view, a funo OnUpdate ser chamada para todas as views que estiverem associadas ao documento exceto a view que indicada pelo pnteiro.
1. Na descrio da classe doc, declare seus membros de dados. Esses membros de dados sero utilizados para o armazenamento primrio de seu aplicativo.
1999-2001 Bernardi, A.
Captulo 6
113
2. Sobrecarregue a funo virtual OnInitialUpdate na classe derivada de CView. A estrutura das aplicaes chama esta funo documento serem inicializados ou lidos do disco. 3. Na classe derivada de CView, permita que as mensagens de comando, mensagens do Windows e mtodo OnDraw alterem diretamente os membros de dados da classe doc utilizando a funo GetDocument para acessar o objeto documento. aps os membros de dados do
3 A classe CFormView
A classe CFormView uma classe view til pois contm muitas das caractersticas das caixas de dilogos. Como uma classe derivada de CDialog, uma classe derivada de CFormView associada a um recurso de dilogo que define as caractersticas de sua janela alm de enumerar seus controles. A classe CFormView suporta as mesmas funes DDX e DDV discutidas no captulo 5 para as caixas de dilogo. OBS: Quando o AppWizard cria um dilogo que ser associado a uma FormView, ele altera corretamente as propriedades que esse dilogo deve obedecer. Se um recurso de dilogo for criado via o Editor de dilogos as seguintes propriedades devem ser respeitadas para o perfeito funcionamento desse recurso quando associado a uma FormView: Style = Child Border = None Visible = desselecionado Um objeto do tipo CFormView recebe as notificaes tanto dos controles como da estrutura das aplicaes. A classe CFormView derivada da classe CView e no da classe CDialog, portanto as funes membros de CDialog OnInitDialog, OnOK e OnCancel no esto presentes nos objetos do tipo formview. Alm da funo UpdateData e DDX no serem chamadas automaticamente. Portanto essas funes devem ser manipuladas pelo programador no tempo certo em resposta as notificaes dos controles e comandos. O AppWizard pode ser utilizado para gerar um aplicativo cuja classe base para a view seja uma CFormView. Quando A CFormView for selecionada o AppWizard gera um recurso de dilogo com as propriedades j corretamente selecionadas. O prximo passo seria utilizar o ClassWizard para mapear as mensagem e adicionar os membros de dados com seus respectivos critrios de validao.
1999-2001 Bernardi, A.
Captulo 6
114
4 A classe CObject
Ao observar a hierarquia de classes da MFC, note que a classe CObject aparece bem no topo e muitas classes so derivadas dela, o que a considerar como a classe raiz. Quando uma classe derivada de CObject ela recebe caractersticas importantes, Muitos desses benefcios sero mostrados em captulos posteriores. Neste captulo sero abordadas as caractersticas de diagnstico por esvaziamento e a opo de utilizar objetos desse tipo como elementos de colees.
int nContador = 10; CString str(total); TRACE("Contador = %d, String = %s\n", nContador, str);
1999-2001 Bernardi, A.
Captulo 6
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos int nContador = 10; CString str(total); #ifdef _DEBUG afxDump << Contador = << nContador << String = << str << \n; #endif // _DEBUG
115
Ambos, afxDump e cout, utilizam o mesmo operador de insero (<<), porm no compartilham seu cdigo. O objeto cout parte da biblioteca iostream do Visual C++, enquanto que o objeto afxDump parte da biblioteca MFC. Classes que no so derivadas de CObject, possuem operadores de insero para objetos do tipo CDumpContext.
#ifdef _DEBUG afxDump << event; // event um objeto do tipo CEvent #endif // _DEBUG
A funo virtual Dump de CObject ser chamada. Se ela no foi sobrecarregada em CEvent, no sero obtidas muitas informaes, exceto o endereo do objeto. Entretanto se ela foi sobrecarregada, podemos obter o estado interno do Objeto. O exemplo a seguir exibe uma funo Dump para a classe CEvent:
#ifdef _DEBUG void CEvent::Dump(CDumpContext& dc) const { CObject::Dump(dc); dc << "tempo = " << m_nTime << "\n"; } #endif // _DEBUG
A funo Dump da classe base (CObject) imprime uma linha como esta:
a CObject at $762A60
1999-2001 Bernardi, A.
Captulo 6
116
Se as macros DECLARE_DINAMIC tivesse sido clamada na definio da classe CEvent e a macro IMPLEMENT_DINAMIC na implementao de CEvent, a linha anterior seria mostrada da seguinte forma:
a CEvent at $762A60
6 Exemplo Curso6A
Este exemplo trata de uma interao simples entre Documentos e Vistas. A classe CCurso6ADoc, derivada de CDocument, contm um objeto do Tipo CEstudante. A classe CEstudante representa um registro de um estudante composto por dois membros, um CString para representar o nome e um inteiro para representar a nota. A classe CCurso6AView, derivada de uma CFormView contm uma representao visual do registro, com caixas de edio para representar o nome e nota. O Boto Enter, atualiza os dados do documento com o contedo das caixas de edio. A figura a seguir mostra o programa Curso6A em execuo:
1999-2001 Bernardi, A.
Captulo 6
117
1999-2001 Bernardi, A.
Captulo 6
118
6.2 Passo 2 Utilize o editor de menus para acrescentar uma opo ao menu Edit
Excluir as opes constantes no menu Edit e inserir a opo Limpar Tudo como mostrado abaixo:
Utilize
constante
padro
sugerida
pela
estrutura
das
aplicaes
ID_EDIT_LIMPARTUDO. Edite a caixa de texto Prompt para torn-lo igual a caixa de propriedades abaixo:
1999-2001 Bernardi, A.
Captulo 6
119
Certifique-se que as propriedades do dilogo que ser a base da FormView sejam exatamente como as mostradas na figura a seguir.
6.4 Passo 4 Utilize o ClassWizard para mapear as mensagens para a classe CCurso6AView
Selecione a classe CCurso6AView e adicione os manipuladores para as mensagens listadas na tabela abaixo. Aceite os nomes padres sugeridos pelo ClassWizard.
6.5 Passo
5 Utilize o
1999-2001 Bernardi, A.
Captulo 6
120
Para a varivel membro m_nNota, entre os valores 0 e 100, nas caixas de edio Minimum Value e Maximum Value respectivamente.
6.6 Passo 6 Utilize o ClassWizard para sobrecarregar a funo membro virtual OnInitialUpdate da classe CCurso6AView
Selecione a classe CCurso6AView na lista Object IDs e localize a entrada para a funo virtual OnInitialUpdate na lista Messages e sobrecarregue essa funo para a classe.
6.7 Passo
Adicione
prottipo
para
funo
membro
UpdateControlsFromDoc
Na janela ClassView do Workspace, pressione o boto direito do mouse sobre a classe CCurso6AView, e selecione a opo Add Member Function. Preencha os dados do dilogo com os valores mostrados abaixo.
// Funo chamada durante inicializao void CCurso6AView::OnInitialUpdate() { UpdateControlsFromDoc() ; } // Funo chamada por OnInitialUpdate e OnEditLimpartudo void CCurso6AView::UpdateControlsFromDoc() { CCurso6ADoc* pDoc = GetDocument(); m_strNome = pDoc->m_estudante.m_strNome; m_nNota = pDoc->m_estudante.m_nNota; UpdateData(FALSE); // Atualizar a tela via DDX (inicializao) }
1999-2001 Bernardi, A.
Captulo 6
121
A funo OnEnter substitui a OnOK, como descrito no captulo anterior. Essa funo responsvel por transferir os dados das caixas de edio para as variveis membros da classe Doc. Edite o cdigo dessa funo para torn-la como abaixo:
void CCurso6AView::OnEnter() { CCurso6ADoc* pDoc = GetDocument(); UpdateData(TRUE); // Retornar dados da tela pDoc->m_estudante.m_strNome = m_strNome; pDoc->m_estudante.m_nNota = m_nNota; }
Em um aplicativo com mltiplas views, a funo OnEditLimpartudo deve ser mapeada dentro da classe document, como este exemplo contm apenas uma view associada ao documento ela pode ser mapeada dentro da view. A funo OnUpdateEditLimpartudo chamada pela estrutura das aplicao para desabilitar a opo do menu se o objeto estudante estiver vazio. Edite seus cdigos para torn-los como mostrado abaixo:
void CCurso6AView::OnEditLimpartudo() { GetDocument()->m_estudante = CEstudante(); // cria novo objeto vazio UpdateControlsFromDoc() ; } void CCurso6AView::OnUpdateEditLimpartudo(CCmdUI* pCmdUI) { pCmdUI->Enable( GetDocument()->m_estudante != CEstudante() ); }
6.9 Passo 9 Edite o projeto Curso6A para adicionar os arquivos para a classe CEstudante
A implementao da classe CEstudante serve como um bom guia para a representao de objetos do mundo real dentro de um programa de computador. Arquivo de Descrio da Classe CEstudante, Estudante.h
// // Arquivo de descrio da classe CEstudante // // Estudante.h #ifndef _CURSOVC_CESTUDANTE #define _CURSOVC_CESTUDANTE class CEstudante : public CObject { DECLARE_DYNAMIC(CEstudante) public: CString m_strNome; int m_nNota; // Construtor Padro CEstudante()
1999-2001 Bernardi, A.
Captulo 6
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos { m_strNome = ""; m_nNota = 0; } // Construtor com parmetros CEstudante(const char* szName, int nGrade) : m_strNome(szName) { m_nNota = nGrade; } // Construtor de Inicializao CEstudante(const CEstudante& s) : m_strNome(s.m_strNome) { m_nNota = s.m_nNota; } // Operador = (Atribuio) const CEstudante& operator =(const CEstudante& s) { m_strNome = s.m_strNome; m_nNota = s.m_nNota; return *this; } // Operador == (Comparao) BOOL operator ==(const CEstudante& s) const { if ((m_strNome == s.m_strNome) && (m_nNota == s.m_nNota)) { return TRUE; } else { return FALSE; } } // Operador != (Comparao) BOOL operator !=(const CEstudante& s) const { // Basta utilizar uma negao (!) com o operador == j implementado return !(*this == s); } #ifdef _DEBUG void Dump(CDumpContext& dc) const; #endif // _DEBUG }; #endif // _CURSOVC_CESTUDANTE
122
// Arquivo de implementao da Classe CEstudante // Estudante.cpp #include "stdafx.h" #include "Estudante.h" IMPLEMENT_DYNAMIC(CEstudante, CObject) #ifdef _DEBUG void CEstudante::Dump(CDumpContext& dc) const { CObject::Dump(dc); dc << "m_strNome = " << m_strNome << "\nm_nNota = " << m_nNota; } #endif // _DEBUG
1999-2001 Bernardi, A.
Captulo 6
123
Aps a edio desses arquivos selecione a opo Add To Project, no menu Project, em seguida escolha a opo Files e selecione os arquivos Estudante.h e Estudante.cpp. O Developer Studio acrescenta os nomes dos arquivos ao projeto e quando ele for compilado os arquivos tambm o sero.
O construtor da classe estudante ser chamado no momento da criao do objeto documento assim como o destrutor tambm ser chamado ao objeto documento ser destrudo.
Para efeito de visualizao do funcionamento do programa, utiliza-se o destrutor da classe doc para chamar a Funo Dump, que tambm deve se encarregar de mostrar o contedo do objeto estudante instanciado durante a seo do programa. Altere o destrutor ~CCurso6ADoc() e a funo Dump para torn-las como descrito abaixo:
CCurso6ADoc::~CCurso6ADoc() { #ifdef _DEBUG Dump(afxDump); #endif //_DEBUG } void CCurso6ADoc::Dump(CDumpContext& dc) const { CDocument::Dump(dc); dc << "\n" << m_estudante << "\n"; }
1999-2001 Bernardi, A.
Captulo 6
124
a CCurso6ADoc at $7601C0 m_strTitle = Untitled m_strPathName = m_bModified = 0 m_pDocTemplate = $760E00 a CEstudante at $760214 m_strNome = Antenor Jos m_nNota = 75
125
5. Na descrio da classe derivada de CDocument, permita que as mensagens de comando atualizem os membros de dados da classe doc. Porm certifique-se de chamar o manipulador da mensagem CDocument::UpdateAllViews antes de sair da funo que mapeia um comando.
8 A funo CDocument::DeleteContents
Em algum ponto do programa ser necessrio um funo para excluir todos os dados de seu documento. Isto poderia se conseguido atravs da escrita de uma funo membro privada, entretanto a estrutura das aplicaes declara a funo virtual DeleteContents para a classe CDocument. A estrutura das aplicaes faz a chamada de sua funo sobrecarregada quando o documento fechado e em outras oportunidades que sero comentadas no prximo captulo.
1999-2001 Bernardi, A.
Captulo 6
126
As funes membros da classe CObList utilizadas para esta aplicao limitam-se a AddTail() ou AddHead() e RemoveRead() ou RemoveTail(), bem como o membro IsEmpty() para controlar um loop para a remoo dos elementos.
CEvent * pEvent; POSITION pos = eventList.GetHeadPosition(); while (pos != NULL) { pEvent = (CEvent *) eventList.GetNext(pos); pEvent->PrintTime(); }
A funo GetNext() retorna o ponteiro para o elemento da lista e incrementa a varivel pos para o prximo elemento. Quando no necessrio incrementar o ponteiro deve-se utilizar a funo membro GetAt().
O primeiro parmetro a classe base utilizada para a coleo, e o segundo parmetro se refere ao tipo da coleo, ou seja o valor utilizado como retorno ou como parmetro. Ao utilizar o template declarado acima, o compilador garante que todas as funes membro da lista retornem um ponteiro para CEvent, no necessitando portanto de um 1999-2001 Bernardi, A. Captulo 6
127
operador de casting para converter o retorno da funo. Por exemplo o seguinte cdigo verdadeiro.
pEvent = m_pEventList.GetNext(pos);
Para manter uma notao mais simples possvel utilizar a declarao typedef para gerar o que mostrado a seguir:
CEventList m_pEventList;
10 Exemplo Curso6B
Este exemplo possui algumas diferenas bsicas em relao ao anterior, sendo elas:
Ao invs de conter um nico objeto CEstudante incorporado, a classe doc possui agora uma lista de objetos do tipo CEstudante. Essa a principal vantagem de se utilizar classes em vez de simplesmente adicionar o nome e a nota como uma varivel membro da classe doc; Possui uma barra de ferramentas que permite o usurio navegar atravs da lista; O aplicativo foi reformulado para permitir o uso de mltiplas views. Notar que o comando de menu Edit Clear All, est mapeado agora para a classe doc, alm das funes UpdateAllViews e OnUpdate serem utilizadas em conjunto. A janela do aplicativo mostrada na Figura 50, possui a barra de ferramentas como diferena bsica ao aplicativo Curso6A, alm de que os botes da barra ficam habilitados apropriadamente apenas quando devem realizar algum evento.
1999-2001 Bernardi, A.
Captulo 6
128
1999-2001 Bernardi, A.
Captulo 6
129
1999-2001 Bernardi, A.
Captulo 6
130
As propriedades de cada um dos itens que sero adicionados devem estar de acordo com a tabela descrita a seguir. Os identificadores so criados automaticamente quando se acrescenta um Capition ao item de menu.
Prompt Volta ao incio da lista de estudantes.\nIncio Avana para o ultimo registro da lista.\nFinal
ID_ESTUDANTE_ANTERIOR &Anterior Retorna ao registro anterior na lista.\nAnterior &Prximo Mover para o prximo registro na lista.\nPrximo &Inserir Excluir Insere um novo registro a lista.\nInserir Excluir o registro atual.\nExcluir
Para acrescentar um boto basta selecionar o boto vazio e desenhar algum cone sobre ele; Para excluir um boto basta arrast-lo para fora da barra de ferramentas; 1999-2001 Bernardi, A. Captulo 6
131
Para criar um separador arraste lateralmente um dos botes que desejado um espao entre eles. Altere as propriedades dos botes (ID) para que eles possuam as mesmas funes do menu. Obs.: Ao alterar o ID o prompt deve aparecer automaticamente, pois j est associado ao mesmo.
Boto
Prompt Volta ao incio da lista de estudantes.\nIncio Avana para o ultimo registro da lista.\nFinal Retorna ao registro anterior na lista.\nAnterior Mover para o prximo registro na lista.\nPrximo Insere um novo registro a lista.\nInserir Excluir o registro atual.\nExcluir
Obs.: Este passo semelhante utilizado no exemplo Curso6A . 1999-2001 Bernardi, A. Captulo 6
132
10.2 Cdigo
As seguintes classes sero alteradas/criadas para atender os requisitos de cdigo deste exemplo:
Arquivo de cabealho
Curso6BDoc.h Curso6BView.h Estudante.h StdAfx.h
Arquivo fonte
Curso6BDoc.cpp Curso6BView.cpp Estudante.cpp StdAfx.cpp
Classes
CCurso6bDoc CCurso6bView CEstudante CEstudanteList
Descrio
Interface com o documento. (Dados) Interface com o usurio. (Janela) Registro de um estudante. Coleo de Registros. Arquivos de incluso padro.
};
#include <afxtempl.h>
1999-2001 Bernardi, A.
Captulo 6
133
Alterar o Construtor da classe para permitir o uso do contexto Dump, o cdigo mostrado a seguir:
CCurso6BDoc::CCurso6BDoc() { TRACE("Dentro do construtor da classe CCurso6BDoc\n"); #ifdef _DEBUG afxDump.SetDepth(1); // Garante o dump dos elementos da lista #endif // _DEBUG }
Utilize o ClassWizard para mapear o comando Limpar do menu Editar, conforme tabela mostrda a seguir;
Mensagem COMMAND
UPDATE_COMMAND_UI OnUpdateEditLimpartudo
Utilize o ClassWizard para sobrecarregar a funo virtual DeleteContents; Edite os cdigos das funes geradas para torn-las como a seguir:
void CCurso6BDoc::DeleteContents() { #ifdef _DEBUG Dump(afxDump); #endif // Excluindo os elementos da lista. while (m_estudanteList.GetHeadPosition()) { delete m_estudanteList.RemoveHead(); } } void CCurso6BDoc::OnEditLimpartudo() { DeleteContents(); // Esvaziar a lista UpdateAllViews(NULL); // Atualizar todas as janelas } void CCurso6BDoc::OnUpdateEditLimpartudo(CCmdUI* pCmdUI) { pCmdUI->Enable(!m_estudanteList.IsEmpty()); }
Edite o arquivo Curso6BDoc.h, para acrescentar as seguintes caractersticas: 1. Acescentar o include para a classe CEstudante ao incio do arquivo:
#include "Estudante.h"
1999-2001 Bernardi, A.
Captulo 6
134
2. Incluir o mtodo GetList(), que por ser um forma de acesso a um atributo da classe fica implementado de forma inline. O seguinte Cdigo deve ser acrescentado:
void CCurso6BDoc::Dump(CDumpContext& dc) const { CDocument::Dump(dc); dc << "\n" << m_estudanteList << "\n"; }
Utilizar o ClassWizard para mapear a mensagem BN_CLICKED do identificador IDC_LIMPAR (duplo-clique) e adicione a funo descrita na tabela abaixo:
Identificador IDC_LIMPAR
Mensagem BN_CLICKED
1999-2001 Bernardi, A.
Captulo 6
135
Utilizar o ClassWizard para mapear os comandos (COMMAND) do menu (duploclique) para as funes descritas na tabela a seguir:
Utilizar
ClassWizard
para
mapear
as
atualizaes
dos
comandos
Mensagem
Funo Membro
UPDATE_COMMAND_UI OnUpdateEstudanteInicio UPDATE_COMMAND_UI OnUpdateEstudanteFinal UPDATE_COMMAND_UI OnUpdateEstudanteInicio UPDATE_COMMAND_UI OnUpdateEstudanteFinal UPDATE_COMMAND_UI OnEstudanteExcluir
void CCurso6BView::OnLimpar() { TRACE("Dentro de CCurso6BView::OnLimpar\n"); LimparItem(); } // void CCurso6BView::OnEstudanteInicio() { TRACE("Dentro de CCurso6BView::OnEstudanteInicio\n"); // este teste necessrio para eliminar problemas com a lista vazia if (!m_pList->IsEmpty()) { m_position = m_pList->GetHeadPosition(); GetItem(m_position); } } void CCurso6BView::OnEstudanteFinal() { TRACE("Dentro de CCurso6BView::OnEstudanteFinal\n");
1999-2001 Bernardi, A.
Captulo 6
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos if (!m_pList->IsEmpty()) { m_position = m_pList->GetTailPosition(); GetItem(m_position); } } // void CCurso6BView::OnEstudanteAnterior() { TRACE("Dentro de CCurso6BView::OnEstudanteAnterior\n"); POSITION pos; if ((pos = m_position) != NULL) { m_pList->GetPrev(pos); if (pos) { GetItem(pos); m_position = pos; } } } // void CCurso6BView::OnEstudanteProximo() { POSITION pos; TRACE("Dentro de CCurso6BView::OnEstudanteProximo\n"); if ((pos = m_position) != NULL) { m_pList->GetNext(pos); if (pos) { GetItem(pos); m_position = pos; } } } // void CCurso6BView::OnEstudanteInserir() { TRACE("Dentro de CCurso6BView::OnEstudanteInserir\n"); InserirItem(m_position); GetDocument()->SetModifiedFlag(); GetDocument()->UpdateAllViews(this); } // void CCurso6BView::OnEstudanteExcluir() { // Excluir o item atual e reposiciona no prximo ou no incio POSITION pos; TRACE("Dentro de CCurso6BView::OnEstudanteExcluir\n"); if ((pos = m_position) != NULL) { m_pList->GetNext(pos); //guarda a posio do prximo elemento if (pos == NULL) // verifica se existe o prximo { pos = m_pList->GetHeadPosition(); TRACE("GetHeadPos = %ld\n", pos); if (pos == m_position) { pos = NULL; } } GetItem(pos); // posiciona no novo item CEstudante* ps = m_pList->GetAt(m_position); m_pList->RemoveAt(m_position); // faz a excluso do item delete ps; // exclui o ponteiro
136
1999-2001 Bernardi, A.
Captulo 6
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos m_position = pos; GetDocument()->SetModifiedFlag(); GetDocument()->UpdateAllViews(this); } }
137
// void CCurso6BView::OnUpdateEstudanteInicio(CCmdUI* pCmdUI) { // chamado durante um processo idle e quando o menu Estudante aberto POSITION pos; // habilita o boto se a lista no estiver vazia e o no estivar no // incio da lista. pos = m_pList->GetHeadPosition(); pCmdUI->Enable((m_position != NULL) && (pos != m_position)); }
// void CCurso6BView::OnUpdateEstudanteFinal(CCmdUI* pCmdUI) { // chamado durante um processo idle e quando o menu Estudante aberto POSITION pos; // habilita o boto se a lista no estiver vazia e o final da // lista no foi atingido. pos = m_pList->GetTailPosition(); pCmdUI->Enable((m_position != NULL) && (pos != m_position)); }
// void CCurso6BView::OnUpdateEstudanteExcluir(CCmdUI* pCmdUI) { // chamado durante um processo idle e quando o menu Estudante aberto // habilita o boto se a posio no for nula pCmdUI->Enable(m_position != NULL); }
Utilize
ClassWizard
para
sobrecarregar
funo
membro
virtual
OnInitialUpdate da classe CCurso6AView Selecione a classe CCurso6AView na lista Object IDs e localize a entrada para a funo virtual OnInitialUpdate na lista Messages e sobrecarregue essa funo para a classe. Adicione o prottipo para a funo membro UpdateControlsFromDoc Na janela ClassView do Workspace, pressione o boto direito do mouse sobre a classe CCurso6AView, e selecione a opo Add Member Function. Preencha os dados do dilogo com os valores mostrados abaixo.
Edite o arquivo Curso6AView.cpp O ClassWizard cria o esqueleto da funo OnInitialUpdate, e o ClassView gera o esqueleto da funo UpdateControlsFromDoc. Utilize o editor para tornar as funes citadas como mostrado abaixo: 1999-2001 Bernardi, A. Captulo 6
138
// Funo chamada durante inicializao void CCurso6AView::OnInitialUpdate() { UpdateControlsFromDoc() ; } // Funo chamada por OnInitialUpdate e OnEditLimpartudo void CCurso6AView::UpdateControlsFromDoc() { CCurso6ADoc* pDoc = GetDocument(); m_strNome = pDoc->m_estudante.m_strNome; m_nNota = pDoc->m_estudante.m_nNota; UpdateData(FALSE); // Atualizar a tela via DDX (inicializao) }
Edite o arquivo Curso6BView.h, para acrescentar as seguintes caractersticas: 1. Adicionar os membros de Dados, m_position e m_pList:
protected: POSITION m_position; // Posio atual no documento CEstudanteList* m_pList; // copiado do documento
protected: virtual void LimparItem(); virtual void InserirItem(POSITION position); virtual void GetItem(POSITION position);
Edite o arquivo Curso6BView.cpp, para um corpo para as funes qie foram declaradas no .h. O Cdigo para essas funes mostrado a seguir:
// void CCurso6BView::LimparItem() { m_strNome = ""; m_nNota = 0; UpdateData(FALSE); } // void CCurso6BView::InserirItem(POSITION position) { if (UpdateData(TRUE)) { // UpdateData retorna FALSE se algum erro for detectado CEstudante* pStudent = new CEstudante; pStudent->m_strNome = m_strNome; pStudent->m_nNota = m_nNota; m_position = m_pList->InsertAfter(m_position, pStudent); } } // void CCurso6BView::GetItem(POSITION position) { if (position) // testa se a posio diferente de NULL {
1999-2001 Bernardi, A.
Captulo 6
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos CEstudante* pStudent = m_pList->GetAt(position); m_strNome = pStudent->m_strNome; m_nNota = pStudent->m_nNota; } else { LimparItem(); } UpdateData(FALSE); }
139
Dentro do construtor da classe CCurso6BDoc Dentro do construtor de CCurso6BView Dentro de CCurso6BDoc::OnNewDocument a CCurso6BDoc at $7601C0 m_strTitle = Untitled m_strPathName = m_bModified = 0 m_pDocTemplate = $760E00 with view $7612E0 a CObList at $760214 with 0 elements Dentro de CCurso6BView::OnInitialUpdate Dentro de CCurso6BView::OnUpdate Dentro de CCurso6BView::OnEstudanteInserir Dentro de CCurso6BView::OnEstudanteInserir a CCurso6BDoc at $7601C0 m_strTitle = Untitled m_strPathName = m_bModified = 1 m_pDocTemplate = $760E00 a CObList at $760214 with 2 elements a CEstudante at $762E80 m_strNome = Teste de nome m_nNota = 44 a CEstudante at $762640 m_strNome = Teste de Nota 100 m_nNota = 100 Warning: destroying an unsaved document.
Utilize o programa para inserir vrios dados e navegar por eles utilizando os botes na barra ou os itens do menu. Notar que quando o final da lista atingido as opes prximo e final ficam desativadas, assim como quando a lista est no incio, as opes Anterior e Incio tambm esto desativadas. Isto se deve ao fato do Windows chamar durante um processo de idle, as funes designadas em ON_UPDATE_COMMAND_UI. No interior dessas funes fica o cdigo para habilitar ou desabilitar os respectivos Comandos. 1999-2001 Bernardi, A. Captulo 6
140
11 Exerccio proposto:
Modificar o programa Curso6B para permitir que ele tenha a caracterstica de alterar um valor de um elemento da lista. Voc deve criar o item de menu bem como o boto na barra de ferramentas para gerar este comando.
1999-2001 Bernardi, A.
Captulo 6
141
Como deve Ter sido notado, todos os exemplos gerados at agora possuem um menu File com os comandos familiares New, Open, Save e Save As. Neste captulo mostrado como os aplicativos podem responder leitura e gravao de documentos. O exemplo desse captulo Curso7A um aplicativo do tipo SDI (Single Document Interface) baseado no programa Curso6B do captulo anterior. O programa utiliza o documento de lista de alunos com uma classe view derivada a partir de CFormView. Porem a lista de alunos poder agora ser lida e escrita no disco atravs de um processo chamado serializao.
1999-2001 Bernardi, A.
Captulo 7
142
Entre a funo Serialize e o objeto CFile h um objeto de arquivamento (CArchive), como mostrado na Figura 53 abaixo. O objeto CArchive coloca dados em buffers para o objeto CFile, mantendo um flag interno que indica se o arquivamento envolve um armazenamento (gravao em disco) ou um carregamento (leitura no disco). A estrutura das aplicaes se encarrega da construo dos Objetos CFile e CArchive, abrindo o arquivo em disco para o objeto CFile e associando o objeto de arquivamento ao arquivo. Ao ser utilizada a funo Serialize, ser necessrio apenas carregar ou armazenar dados no objeto de arquivamento.
1999-2001 Bernardi, A.
Captulo 7
143
A classe CEstudante deve possuir a funo Serialize para permitir a capacidade de armazenamento de seus objetos, nossa tarefa implement-la. Devido ao fato da funo membro Serialize ser um membro virtual da classe base CObject devemos garantir que o valor e os tipos de parmetros retornados coincidam com a declarao de CObject. A seguir encontra-se o cdigo da funo Serialize a ser implementada para a classe CEstudante.
void CEstudante::Serialize(CArchive& ar) { if (ar.IsStoring()) ar << m_strNome << m_nNota; else ar >> m_strNome >> m_nNota; }
Normalmente as funes de serializao chamam a funo Serialize de suas classes bsicas. Por exemplo se a classe CEstudante fosse derivada de CPessoa, a primeira linha da funo Serialize seria a seguinte:
CPessoa::Serialize(ar);
As funes Serialize das classes CObject e CDocument no executam aes teis, portanto no so chamadas.
Se uma coleo possuir ponteiros de objetos pertencentes a varias classes (todas derivadas de CObject), em essncia os nomes individuais das classes sero armazenados no objeto de arquivamento, de modo que os objetos possam ser construdos adequadamente com o uso do construtor apropriado para a classe. Se um objeto de armazenamento, como um documento, possuir uma coleo interna, os dados carregados sero anexados coleo existente. Pode ser necessrio esvaziar a coleo antes de fazer o carregamento a partir do objeto de
1999-2001 Bernardi, A.
Captulo 7
144
arquivamento. Isso normalmente ser feito em uma funo DeleteContents, a qual ser chamada pela estrutura das aplicaes. Se um objeto de armazenamento possuir um ponteiro para uma coleo, ser construdo um novo objeto de coleo quando o operador de extrao carregar dados a partir do objeto de arquivamento. Um ponteiro para a nova coleo ser armazenado no membro de dados de ponteiro do objeto de armazenamento. Pode ser necessria a destruio do objeto antigo de coleo (aps o mesmo ter sido esvaziado) antes de ser feito o carregamento a partir do objeto de arquivamento. Quando uma coleo de ponteiros CObject for carregada a partir de um objeto de arquivamento, os seguintes passos de processamento iro ocorrer para cada objeto contido na coleo: A classe do objeto ser identificada. Ser feita a alocao de um espao de armazenamento no heap para o objeto. Os dados do objeto sero carregados na rea de armazenagem recmalocada. Um ponteiro para o novo objeto ser armazenado na coleo.
2 Aplicativo SDI
J vimos muitas aplicaes da SDI que possuem uma classe de documento e uma classe de vista. Vamos manter o uso de apenas uma classe de vista neste captulo, mas iremos explorar as inter-relaes existentes entre os elementos da estrutura das aplicaes
1999-2001 Bernardi, A.
Captulo 7
145
criados para os programas. Como por exemplo o objeto aplicativo, a janela principal (mainframe), o documento, a vista e menu.
CMyApp theApp;
Esse o mecanismo pelo qual a MFC inicializa seus aplicativos. A classe CMyApp ser derivada da classe CWinApp, com theApp sendo uma instncia (objeto) da classe declarada de forma global. O Objeto global denominado objeto do aplicativo para Windows. Ao iniciar o programa o objeto global ser criado e a estrutura das aplicaes se encarrega de chamar a funo membro InitInstance, onde feita a conexo entre os elementos frame, doc e view, atravs do chamado Template. Pode-se entender como Template a aparncia de um programa. Aps feitas as conexes, a estrutura das aplicaes chama o mtodo Run que mantm o aplicativo ativo e inicia o processo de envio de mensagens de janelas e de comandos.
1999-2001 Bernardi, A.
Captulo 7
146
armazenamento (gravao). O item de menu File Save As ser processado de maneira semelhante; este item de menu ser mapeado para a funo OnFileSaveAs de CDocument, a qual chama OnSaveDocument. Para esta situao, a estrutura das aplicaes executa todo o gerenciamento de arquivos necessrio ao salvamento do documento no disco.
3 Exemplo Curso7A
Este exemplo similar ao programa Curso6B.
1999-2001 Bernardi, A.
Captulo 7
147
Alterar a string que vai ser associada aos documento do exemplo para 07A durante o passo 4 do AppWizard, atravs do boto Advanced... que ao ser pressionado exibe a caixa de dilogo mostrada na Figura 54. No passo 6 do AppWizard, alterar a classe base de CCurso7AView para uma CFormView, como mostrado no exemplo Curso6A e Curso6B. A tela com o resumo dos arquivos e caractersticas acrescentadas para o programa Curso7A est mostrada na
3.2 Recursos
Os recursos utilizados para programa so os mesmos utilizados no exemplo Curso6B. Utilize o editor de recursos para copi-los para o exemplo Curso7A, atravs da abertura do arquivo curso6B.rc e explorao de seu contedo.
Figura 54 - Dilogo para alterao das strings relacionadas com o modelo de Documento.
1999-2001 Bernardi, A.
Captulo 7
148
3.3 Cdigo
Os requisitos de cdigo que diferem do exemplo anterior sero listados a seguir, respeitando a notao de realado em cinza o cdigo que deve ser substitudo ou alterado em relao ao exemplo Curso6B.
// // Arquivo de descrio da classe CEstudante // // Estudante.h #ifndef _CURSOVC_CESTUDANTE #define _CURSOVC_CESTUDANTE class CEstudante : public CObject {
1999-2001 Bernardi, A.
Captulo 7
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos DECLARE_SERIAL(CEstudante) public: CString m_strNome; int m_nNota; // Construtor Padro CEstudante() { m_strNome = ""; m_nNota = 0; } // Construtor com parmetros CEstudante(const char* szName, int nGrade) : m_strNome(szName) { m_nNota = nGrade; } // Construtor de Inicializao CEstudante(const CEstudante& s) : m_strNome(s.m_strNome) { m_nNota = s.m_nNota; } // Operador = (Atribuio) const CEstudante& operator =(const CEstudante& s) { m_strNome = s.m_strNome; m_nNota = s.m_nNota; return *this; } // Operador == (Comparao) BOOL operator ==(const CEstudante& s) const { if ((m_strNome == s.m_strNome) && (m_nNota == s.m_nNota)) { return TRUE; } else { return FALSE; } } // Operador != (Comparao) BOOL operator !=(const CEstudante& s) const { // Basta utilizar uma negao (!) com o operador == j implementado return !(*this == s); } virtual void Serialize(CArchive& ar); #ifdef _DEBUG void Dump(CDumpContext& dc) const; #endif // _DEBUG }; //fim da declarao da classe CEstudante //Declarao da classe CEstudanteList typedef CTypedPtrList<CObList, CEstudante*> CEstudanteList; #endif // _CURSOVC_CESTUDANTE
149
1999-2001 Bernardi, A.
Captulo 7
150
#include "stdafx.h" #include "Estudante.h" IMPLEMENT_SERIAL(CEstudante, CObject, 0) void CEstudante::Serialize(CArchive& ar) { TRACE("Dentro de CEstudante::Serialize\n"); if (ar.IsStoring()) { ar << m_strNome << m_nNota; } else { ar >> m_strNome >> m_nNota; } } #ifdef _DEBUG void CEstudante::Dump(CDumpContext& dc) const { CObject::Dump(dc); dc << "m_strNome = " << m_strNome << "\nm_nNota = " << m_nNota; } #endif // _DEBUG
// Curso7ADoc.h : interface of the CCurso7ADoc class // ///////////////////////////////////////////////////////////////////////////// #if !defined(AFX_CURSO7ADOC_H) #define AFX_CURSO7ADOC_H #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 #include "Estudante.h" class CCurso7ADoc : public CDocument {
1999-2001 Bernardi, A.
Captulo 7
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos protected: // create from serialization only CCurso7ADoc(); DECLARE_DYNCREATE(CCurso7ADoc) // Attributes public: CEstudanteList* GetList(){ return &m_estudanteList; } // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CCurso7ADoc) public: virtual BOOL OnNewDocument(); virtual void Serialize(CArchive& ar); virtual void DeleteContents(); virtual BOOL OnOpenDocument(LPCTSTR lpszPathName); //}}AFX_VIRTUAL // Implementation public: virtual ~CCurso7ADoc(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: // Generated message map functions protected: //{{AFX_MSG(CCurso7ADoc) afx_msg void OnEditLimpartudo(); afx_msg void OnUpdateEditLimpartudo(CCmdUI* pCmdUI); afx_msg void OnUpdateFileSave(CCmdUI* pCmdUI); //}}AFX_MSG DECLARE_MESSAGE_MAP() private: CEstudanteList m_estudanteList; };
151
///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately before the previous line. #endif // AFX_CURSO7ADOC_H
// Curso7ADoc.cpp : implementation of the CCurso7ADoc class // #include "stdafx.h" #include "Curso7A.h" #include "Curso7ADoc.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif
1999-2001 Bernardi, A.
Captulo 7
152
///////////////////////////////////////////////////////////////////////////// // CCurso7ADoc IMPLEMENT_DYNCREATE(CCurso7ADoc, CDocument) BEGIN_MESSAGE_MAP(CCurso7ADoc, CDocument) //{{AFX_MSG_MAP(CCurso7ADoc) ON_COMMAND(ID_EDIT_LIMPARTUDO, OnEditLimpartudo) ON_UPDATE_COMMAND_UI(ID_EDIT_LIMPARTUDO, OnUpdateEditLimpartudo) ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave) //}}AFX_MSG_MAP END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////////// // CCurso7ADoc construction/destruction CCurso7ADoc::CCurso7ADoc() { TRACE("Dentro do construtor CCurso7ADoc \n"); #ifdef _DEBUG afxDump.SetDepth(1); // garante o esvaziamento da lista #endif // _DEBUG } CCurso7ADoc::~CCurso7ADoc() { } BOOL CCurso7ADoc::OnNewDocument() { TRACE("Dentro do CCurso7ADoc::OnNewDocument\n"); if (!CDocument::OnNewDocument()) return FALSE; // TODO: add reinitialization code here // (SDI documents will reuse this document) return TRUE; }
///////////////////////////////////////////////////////////////////////////// // CCurso7ADoc serialization void CCurso7ADoc::Serialize(CArchive& ar) { TRACE("Dentro do CCurso7ADoc::Serialize\n"); if (ar.IsStoring()) { // TODO: add storing code here } else { // TODO: add loading code here } m_estudanteList.Serialize(ar); } ///////////////////////////////////////////////////////////////////////////// // CCurso7ADoc diagnostics #ifdef _DEBUG void CCurso7ADoc::AssertValid() const { CDocument::AssertValid(); }
1999-2001 Bernardi, A.
Captulo 7
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos void CCurso7ADoc::Dump(CDumpContext& dc) const { CDocument::Dump(dc); dc << "\n" << m_estudanteList << "\n"; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CCurso7ADoc commands void CCurso7ADoc::DeleteContents() { TRACE("Dentro de CCurso7ADoc::DeleteContents\n"); // Excluindo os elementos da lista. while (m_estudanteList.GetHeadPosition()) { delete m_estudanteList.RemoveHead(); } } BOOL CCurso7ADoc::OnOpenDocument(LPCTSTR lpszPathName) { TRACE("Dentro de CCurso7ADoc:: OnOpenDocument \n"); if (!CDocument::OnOpenDocument(lpszPathName)) return FALSE; // TODO: Add your specialized creation code here return TRUE; } void CCurso7ADoc::OnEditLimpartudo() { DeleteContents(); // Esvaziar a lista UpdateAllViews(NULL); // Atualizar todas as janelas } void CCurso7ADoc::OnUpdateEditLimpartudo(CCmdUI* pCmdUI) { pCmdUI->Enable(!m_estudanteList.IsEmpty()); } void CCurso7ADoc::OnUpdateFileSave(CCmdUI* pCmdUI) { // Desabilita o boto da barra de ferramentas se o documento no foi alterado pCmdUI->Enable(IsModified()); }
153
154
Encerre o programa e em seguida inicie-o novamente, abrindo o arquivo salvo anteriormente. Os nomes retornaram? E observe as entradas na janela Debug, que nos do uma pista de como a estrutura das aplicaes manuseia o Salvamento e recuperao em disco.
1999-2001 Bernardi, A.
Captulo 7
155
Neste captulo introduzido um aplicativo usando a interface de mltiplos documentos (MDI Multiple Document Interface) com o uso da MFC, explicando como sero feitas leituras e gravaes nos arquivos de documento. Um aplicativo MDI ser efetivamente o estilo de preferncia para um programa da biblioteca de classes. O AppWizard permite algumas caractersticas especficas aos aplicativos MDI, como o uso do Arrastar e Soltar, e duplo clique no Explorer. Alm disso a maior parte dos exemplos de programa que acompanham o Visual C++ so aplicativos MDI. Vamos abordar ainda neste captulo as similaridades e tambm as diferenas entre aplicativos SDI(Single Document Interface) e MDI. Sugere-se que, antes de ser iniciada o estudo dos aplicativos destinados a MDI, haja uma compreenso completa a respeito dos Aplicativos baseados na SDI, conforme descrito no captulo anterior.
1 Aplicativo MDI
Antes de analisar o cdigo gerado pela biblioteca de classes para os aplicativos MDI, deve haver uma certa familiaridade com a operao de programas do Windows que utilizem a MDI. Observe com cuidado o Developer Studio. Esse um aplicativo MDI cujos "mltiplos documentos" so arquivos contendo cdigos fontes para os programas. Contudo o Developer Studio no representa uma das mais tpicas aplicativos MDI, porque seus documentos so reunidos em projetos. Seria mais interessante examinar o Microsoft Word, ou, ainda melhor, uma aplicao real da MDI da biblioteca de classes - do tipo gerado pelo AppWizard.
1999-2001 Bernardi, A.
Captulo 8
156
Ao Abre uma janela filha para o documento selecionado. Arranja as janelas existentes usando um padro sobreposto (cascata)
1999-2001 Bernardi, A.
Captulo 8
157
Arranja as janelas existentes usando um padro lado a lado (no sobreposto) Arranja as janelas iconizadas na mainframe. Seleciona a janela filha correspondente e traz a mesma para a posio de topo
Se o usurio salvar e fechar as duas janela filhas (e abrir o menu file), o aplicativo ter o aspecto da Figura 58
O menu diferente: a maior parte dos botes existentes na barra de ferramentas se apresenta desativada, e a Barra de ttulo da janela no mostra o nome do arquivo. O usurio praticamente s poder executar duas aes: o incio de um novo documento ou a abertura de um documento j existente no disco. A Figura 59 mostra o aplicativo logo aps a execuo ser iniciada sendo criado um novo documento. A nica janela filha foi maximizada. A nica janela filha vazia possui o nome bsico de documento Curso7. Este nome se baseia no item Doc Type Name selecionado no dilogo classes do AppWizard Curso7. O primeiro arquivo novo Curso71, o segundo ser Curso72 e assim por diante. O usurio normalmente seleciona um nome diferente ao salvar o documento. Os aplicativos MDI geradas com o uso da MFC, assim como acontece no caso de muitos aplicativos comerciais da MDI, iniciam suas operaes com um novo documento vazio. Se for desejado que o aplicativo inicie com a janela mainframe em branco, pode ser alterado o argumento da funo ProcessShellCommand chamado no arquivo de implementao de classe do aplicativo como mostrado no exemplo Curso8A.
1999-2001 Bernardi, A.
Captulo 8
158
1999-2001 Bernardi, A.
Captulo 8
159
Classe Base
Nmero de Objetos
CMDIFrameWnd
CMainFrame
Apenas 1
sim
no
CMDIChildWnd
Sem derivao
no
sim
Pela Estrutura das Aplicaes quando uma nova janela filha for aberta
2 Exemplo Curso8A
O exemplo Curso8A um aplicativo MDI baseado no exemplo anterior Curso7A. Suas principais diferenas so as capacidades de arrastar e soltar, bem como a abertura de um 1999-2001 Bernardi, A. Captulo 8
160
arquivo atravs do Explorer. Notar a diferena dentro da funo InitInstance da classe CCurso8AApp.
1999-2001 Bernardi, A.
Captulo 8
161
1999-2001 Bernardi, A.
Captulo 8
162
1999-2001 Bernardi, A.
Captulo 8
163
1999-2001 Bernardi, A.
Captulo 8
164
BOOL CCurso8AApp::InitInstance() { AfxEnableControlContainer(); // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. #ifdef _AFXDLL // Call this when using MFC in a shared DLL Enable3dControls(); #else // Call this when linking to MFC statically Enable3dControlsStatic(); #endif // Change the registry key under which our settings are stored. // You should modify this string to be something appropriate // such as the name of your company or organization. SetRegistryKey(_T("Local AppWizard-Generated Applications")); // Load standard INI file options (including MRU) LoadStdProfileSettings(); // Register the application's document templates. Document templates // serve as the connection between documents, frame windows and views. CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_CURSO7TYPE, RUNTIME_CLASS(CCurso8ADoc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame RUNTIME_CLASS(CCurso8AView)); AddDocTemplate(pDocTemplate); // create main MDI Frame window CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; // Enable drag/drop open m_pMainWnd->DragAcceptFiles(); // Enable DDE Execute open EnableShellOpen(); RegisterShellFileTypes(TRUE); // Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // nenhum documento vazio ao iniciar o programa if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileNew) cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;
1999-2001 Bernardi, A.
Captulo 8
165
// Dispatch commands specified on the command line if (!ProcessShellCommand(cmdInfo)) return FALSE; // The main window has been initialized, so show and update it. pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->UpdateWindow(); return TRUE; }
1999-2001 Bernardi, A.
Captulo 8
166
Neste captulo abordado uma introduo a utilizao de bancos de dados comerciais, via ODBC (Open Database Connectivity) ou DAO (Data Access Object) utilizando a MFC. As classes que sero utilizadas neste captulo sero derivadas de uma classe CRecordset (CDaoRecordset) e uma classe CRecordView (CDaoRecordView). O exemplo Curso9A mostra uma interao entre essas duas classes a ainda serve como um visualizador de banco de dados. Durante sua criao sero mostrados os passos a serem seguidos para criar um aplicativo simples de banco de dados utilizando a MFC.
2 A Classe CRecordset/CDaoRecordset
Um objeto de CDaoRecordset representa um conjunto de registros selecionados de uma fonte de dados. Conhecidos como "recordsets", objetos de CDaoRecordset esto disponveis nos trs seguintes formatos: Recordsets tipo Table - representa uma tabela bsica que pode ser utilizada para examinar, acrescentar, mudar, ou apagar registros de uma nica tabela de banco de dados. Recordsets tipo Dynaset - o resultado de uma consulta que pode conter registros atualizveis. Este recordsets um conjunto de registros que pode ser utilizado para examinar, acrescentar, mudar, ou apagar registros de tabelas de um banco de dados. Podem conter campos de uma ou mais tabelas de um banco de dados. 1999-2001 Bernardi, A. Captulo 9
167
Recordsets tipo Snapshot - uma cpia esttica de um conjunto de registros que voc pode usar, achar dados ou gerar relatrios. Estes recordsets podem conter campos de uma ou mais tabelas em um banco de dados mas no pode ser atualizado. Cada formato de recordset representa um conjunto de registros definidos no momento em que o mesmo aberto. Quando o registro alterado em recorsets do tipo Table ou Dynaset, essas mudanas sero refletidas no registro do arquivo depois que o recordset for aberto, ou por outros usurios ou por outro recordsets em sua aplicao. (Um recordset de tipo Snapshot no pode ser atualizado.) Voc pode usar CDaoRecordset diretamente ou pode derivar um recordset especfico para seu aplicativo. Possuindo um objeto recordset no aplicativo possvel: Navegar pelos registros. Fixar um ndice e procurar registros rapidamente usando Busca (apenas para recordsets de tipo Table). Encontrar Registros baseado em uma comparao de strings: "<", "<=", "=", ">=", ou " >" (Apenas para os tipos Dynaset, Snapshot). Atualizar os registros e especificar um modo de travamento de registros (menos recordsets tipo Snapshot). Filtrar o recordset para restringir quais registros estaro disponveis na base de dados. Ordenar o recordset. Parametrizar o recordset para personalizar sua seleo com informaes somente disponveis em tempo de execuo do programa. Classe CDaoRecordset prov uma interface semelhante a da classe CRecordset. A diferena principal uma classe CDaoRecordset tem acesso aos dados por um Objeto de Acesso de Dados (DAO) baseado em OLE. Classe CRecordset acessa o DBMS por Open Database Connectivity (ODBC) e driver de ODBC para aquele DBMS. Notar que existem classes distintas na MFC para o acesso a banco de dados via DAO ou ODBC e que as classes de acesso atravs do DAO levam o prefixo "CDao". As classes DAO geralmente oferecem capacidades superiores porque elas so especficas Microsoft Jet DB engine. CDaoRecordset utiliza a DAO record field exchange (DFX) para suportar a leitura e atualizao dos campos de um registro para os membros de uma classe CDaoRecordset ou sua derivada.
1999-2001 Bernardi, A.
Captulo 9
168
3 A Classe CRecordView/CDaoRecordView
Um objeto de CDaoRecordView uma view que exibe registros de banco de dados em controles. Essa view uma form conectada diretamente um objeto de CDaoRecordset. O layout da janela criado a partir de um recurso de modelo de dilogo e exibe os campos do objeto CDaoRecordset em seus controles. O objeto CDaoRecordView usa dialog data exchange (DDX) e DAO record field exchange (DFX) para automatizar o movimento de dados entre os controles no formulrio e os campos do recordset. CDaoRecordView tambm prov um implementao padro destinada a mover ao primeiro, prximo, prvio, ou ltimo registro e uma interface por atualizar vista o registro corrente. Como descrito no item anterior na MFC existem classes distintas para utilizar a interface DAO e ODBC, sendo elas respectivamente uma CDaoRecordView e uma CRecordView. Ambas possuem caractersticas semelhantes porm a interface DAO mais eficiente. A maneira mais fcil de se criar uma RecordView atravs do AppWizard. AppWizard cria a classe RecordView e sua recordset associada como parte do esqueleto de um novo aplicativo, ver mais a frente Exemplo Curso9A. Para os casos em que apenas um formulrio requerido, o AppWizard oferece o meio mais simples de implementar, entretanto necessrio mais de um formulrio para a mesma tabela ou nos casos de vrias tabelas, o ClassWizard oferece uma opo mais flexvel, pois possvel criar uma nova RecordView e decidir qual Recordset estar ligado a ela no momento de sua criao. Se a classe de vista no for criada pelo o AppWizard, possvel cri-la mais tarde utilizando o ClassWizard. Esta caracterstica tambm permite ter mltiplas janelas associadas ao mesmo recordset. A fim de tornar a interface com o usurio mais amigvel, e fcil de movimentar por entre os registros o AppWizard cria recursos itens de menu (e toolbar) para mover ao primeiro, prximo, prvio, ou ltimo registro. Se uma classe derivada de CDaoRecordView for criada utilizando o ClassWizard, necessrio tambm criar estes recursos porm manualmente. CDaoRecordView mantm registrado a posio do usurio no recordset de forma que a RecorView pode atualizar a interface de usurio. Por exemplo quando o usurio move para o final do recordset, a RecordView desabilita a interface do usurio (as opes de menu e botes na Toolbar) para no permitir que o usurio avance alm do final dos registros.
1999-2001 Bernardi, A.
Captulo 9
169
Selecione a utilizao de banco de dados a partir da interface DAO (Figura 68) , e selecione o boto exibidos. para localizar o arquivo que contm os dados a serem
Ao confirmar a localizao dos dados fechando o dilogo mostrado na Figura 68, ser pedido o nome do conjunto de registros (Tabela/Consulta) que ser utilizado como fonte de dados para o programa. (Figura 69), Com a base de dados selecionada, o passo 2 do AppWizard aparece como mostrado na Figura 70, Notar que no passo 6 do AppWizard (Figura 71), a classe me (Base Class), para a classe CCurso9AView, j est selecionada como uma CDaoRecordView e que uma classe CCurso9ASet foi criada pelo AppWizard, com a referncia de onde os dados sero obtidos. Na Figura 72, observe as opes de criao para o exemplo Curso9A.
1999-2001 Bernardi, A.
Captulo 9
170
Figura 68 - Dilogo para seleo do tipo de suporte a banco de dados a ser utilizado.
1999-2001 Bernardi, A.
Captulo 9
171
1999-2001 Bernardi, A.
Captulo 9
172
4.2.2 Cdigo:
Utilize o ClassWizard para conectar as caixas de edio aos campos correspondentes do banco de dados a ser exibido. 1999-2001 Bernardi, A. Captulo 9
173
Selecione as variveis associadas (Figura 74) a tabela de dados para cada um dos identificadores correspondentes as caixas de edio criadas no formulrio. Observe que a varivel criada um ponteiro para um membro da classe Set, e na lista aparecem com um indicador -> antes de seu nome.(Figura 75) Obs: Variveis que existem apenas temporariamente, ou seja no fazem parte da tabela ou um resultado entre elementos da tabela podem ser ainda podem ser criadas diretamente dentro da classe View, o que permite que parte dos dados exibidos na tela sejam resultados de clculos e no necessariamente membros de uma tabela.
1999-2001 Bernardi, A.
Captulo 9
174
1999-2001 Bernardi, A.
Captulo 9
175
5.1.1 Passo 1 Utilize o editor de menus para acrescentar opes ao menu Record:
Selecionar o item Menu do arquivo de recursos e escolher o identificador IDR_MAINFRAME (duplo-clique); Selecionar o submenu Record; Acrescentar os itens de menu como mostrado na figura abaixo;
As propriedades de cada um dos itens que sero adicionados devem estar de acordo com a tabela descrita a seguir. Obs.: os identificadores so criados automaticamente quando se acrescenta um Capition ao item de menu.
1999-2001 Bernardi, A.
Captulo 9
176
Identificador
ID_RECORD_ADD ID_RECORD_DELETE ID_RECORD_REFRESH
Capition
&Add &Delete &Refresh
Prompt
Adicionar novos registros ao Banco de dados.\nAdicionar Excluir o registro atual.\nExcluir Desfazer ultimas alteraes.\nDesfazer
// Implementation public: BOOL Gravar(); virtual ~CAddForm(); // Generated message map functions protected: //{{AFX_MSG(CAddForm) afx_msg void OnRecordAdd(); afx_msg void OnRecordRefresh(); afx_msg void OnRecordDelete(); afx_msg void OnUpdateRecordFirst(CCmdUI* pCmdUI); //}}AFX_MSG //{{AFX_VIRTUAL(CAddForm) virtual void OnInitialUpdate(); // called first time after construct //}}AFX_VIRTUAL DECLARE_MESSAGE_MAP() }; #endif // !defined(AFX_ADDFORM_INCLUDED)
1999-2001 Bernardi, A.
Captulo 9
177
// addform.cpp : implementation of the CAddForm class // #include "stdafx.h" #include "Curso9B.h" #include "addform.h"
//
#ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNAMIC(CAddForm, CDaoRecordView) BEGIN_MESSAGE_MAP(CAddForm, CDaoRecordView) //{{AFX_MSG_MAP(CAddForm) ON_COMMAND(ID_RECORD_ADD, OnRecordAdd) ON_COMMAND(ID_RECORD_REFRESH, OnRecordRefresh) ON_COMMAND(ID_RECORD_DELETE, OnRecordDelete) ON_UPDATE_COMMAND_UI(ID_RECORD_FIRST, OnUpdateRecordFirst) //}}AFX_MSG_MAP END_MESSAGE_MAP() CAddForm::CAddForm(UINT nIDTemplate) : CDaoRecordView(nIDTemplate) { //{{AFX_DATA_INIT(CAddForm) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_bAddMode = FALSE; } CAddForm::~CAddForm() { } BOOL CAddForm::OnMove(UINT nIDMoveCommand) { CDaoRecordset* pRecordset = OnGetRecordset(); if (m_bAddMode) { if (!UpdateData()) return FALSE; try { pRecordset->Update(); } catch (CDaoException* e) { e->ReportError(); e->Delete(); return FALSE; } pRecordset->Requery(); UpdateData(FALSE); m_bAddMode = FALSE; return TRUE; } else { return CDaoRecordView::OnMove(nIDMoveCommand);
1999-2001 Bernardi, A.
Captulo 9
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos } } BOOL CAddForm::RecordAdd() { // If already in add mode, then complete previous new record if (m_bAddMode) OnMove(ID_RECORD_FIRST); OnGetRecordset()->AddNew(); m_bAddMode = TRUE; UpdateData(FALSE); return TRUE; } BOOL CAddForm::RecordDelete() { if (IDYES==AfxMessageBox("Voc tem certeza que deseja excluso?", MB_ICONQUESTION|MB_YESNO)) { CDaoRecordset* pRecordset = OnGetRecordset(); try { pRecordset->Delete(); } catch (CDaoException* e) { e->ReportError(); e->Delete(); return FALSE; } // Move to the next record after the one just deleted pRecordset->MoveNext(); // If we moved off the end of file, then move back to last record if (pRecordset->IsEOF()) try { pRecordset->MoveLast(); } catch (CDaoException* e) { pRecordset->SetFieldNull(NULL); e->ReportError(); e->Delete(); return FALSE; } // If the recordset is now empty, then clear the fields // left over from the deleted record if (pRecordset->IsBOF()) { pRecordset->SetFieldNull(NULL); } UpdateData(FALSE); } return TRUE; }
178
prosseguir
BOOL CAddForm::RecordRefresh() { if (m_bAddMode == TRUE) { OnGetRecordset()->CancelUpdate(); OnGetRecordset()->Move(0); m_bAddMode = FALSE; } // Copy fields from recordset to form, thus
1999-2001 Bernardi, A.
Captulo 9
Curso de Extenso Universitria Visual C++, Microsoft Foundation Classes Fundamentos // overwriting any changes user may have made // on the form UpdateData(FALSE); return TRUE; } void CAddForm::OnRecordAdd() { RecordAdd(); } void CAddForm::OnUpdateRecordFirst(CCmdUI* pCmdUI) { if (m_bAddMode) pCmdUI->Enable(TRUE); else CDaoRecordView::OnUpdateRecordFirst(pCmdUI); } void CAddForm::OnRecordRefresh() { RecordRefresh(); } void CAddForm::OnRecordDelete() { RecordDelete(); } BOOL CAddForm::Gravar() { CDaoRecordset* pRecordset = OnGetRecordset(); if (m_bAddMode) { OnMove(ID_RECORD_LAST); return OnMove(ID_RECORD_LAST); } if (pRecordset->IsBOF() || pRecordset->IsEOF()) return FALSE; pRecordset->Edit(); if (!UpdateData()) return FALSE; try { pRecordset->Update(); } catch (CDaoException* e) { e->ReportError(); e->Delete(); return FALSE; } return TRUE; } void CAddForm::OnInitialUpdate() { CDaoRecordView::OnInitialUpdate(); }
179
1999-2001 Bernardi, A.
Captulo 9
180
No arquivo de Implementao da classe Curso9BView.cpp , trocar todas as ocorrencias de CDaoRecordView por CAddForm.
1999-2001 Bernardi, A.
Captulo 9
181
Projetar um programa com interface MDI para cadastrar uma lista de alunos, com as suas respectivas notas obtidas nos bimestres, calcular a mdia, verificar se o estudante ficou de prova final, calcular a nova mdia e verificar se o estudante foi aprovado. As listas de alunos devem ser gravadas em disco com um arquivo que seja "NomeDisciplina.10A".
2 Observaes
1. As mdias devem ser calculadas utilizando as frmulas convencionais. 2. Utilizar os exemplos do curso como base para a criao desse programa. 3. Gerar uma verso Release do programa para entrega.
1999-2001 Bernardi, A.
182
Bibliografia
Bibliografia consultada
Os seguintes referncia foram utilizadas como base para a construo dessa apostila:
BARKAKATI, : Visual C++, Makron Books HOLZNEI, S.: Programando com Visual C++, LTC Editora, 1993. KRUGLINSKI, D. J.: Explorando o Visual C++, Editora Campus. KRUGLINSKI, D. J.: Inside Visual C++, 4a Ed, Microsoft Press , 1997. WIENER, R. S.: C++ Programao Orientada para Objeto. Manual Prtico e Profissional, Makron Books 1991 BERNARDI, A. : Notas de aula da Disciplina de Programao Avanada.
1999-2001 Bernardi, A.
Bibliografia
183
Anexo I
1999-2001 Bernardi, A.
Anexo I
184
1999-2001 Bernardi, A.
Anexo I
1999-2001 Bernardi, A.
ndice