Hello Word

Aplicações Hello Word são comuns na primeira vez que você faz um programa em determinada linguagem, desenhei um “Hello Word” para MVC.

Vou usar como base para esse programa uma tabela customizada, para te ajudar eu criei um GitHub e coloquei nele o update contendo essa e outras tabelas, se quiser é só fazer o download aqui GitHub e aplicar no seu ambiente.

Passo 01: Includes

O MVC possui um include especifico, nele temos vários defines uteis, sempre que escrevo um programa em MVC uso esse include, o nome é FWMVCDef.CH

Coloque no seu fonte esse include, seu fonte deve ficar assim:

#Include 'Protheus.ch'
#Include 'FWMVCDEF.ch'

User Function CMVC_01()
Return

 

Passo 02:  Browse

Eu já disse que o Browse não é obrigatório, mas vou criar ele nesse exemplo, para que as ações principais do usuário ocorram a partir desse componente.

O foco aqui não é o Browse, então vamos criar um simples, baseado em dicionário de dados e tendo como tabela principal o alias ZB2, referente a Alunos.

User Function CMVC_01()
Local oBrowse
 oBrowse := FWMBrowse():New()
 oBrowse:SetAlias('ZB2')
 oBrowse:SetDescription('Cadastro de Alunos')
 oBrowse:Activate() 
Return

Passo 03: Menu

No menu vamos criar quais ações serão disponibilizadas para o usuário no Browse de Alunos.  Como ja disse anteriomente, o menu é definido dentro da função MenuDef do seu fonte e além disso a função deve sempre retornar um array com as ações a serem disponibilizadas.

O array deve possuir a seguinte estrutura:

  • Coluna 1: Título a ser exibido no botão do browse
  • Coluna 2: Nome da função que será executada quando o usuario clicar no botão
  • Coluna 3: Reservado
  • Coluna 4: Número da operação
  • Coluna 5: Reservado
  • Coluna 6: Reservado

Sendo que, a coluna 4 deve ser preenchida com o número ou o DEFINE de uma das operações abaixo:

  • 1 ou OP_PESQUISAR: Pesquisar
  • 2 ou OP_VISUALIZAR: Visualizar
  • 3 ou OP_INCLUIR: Incluir
  • 4 ou OP_ALTERAR: Alterar
  • 5 ou OP_EXCLUIR: Excluir
  • 8 ou OP_IMPRIMIR: Imprimir
  • 9 ou OP_COPIA : Copia

 

Static Function MenuDef()
Local aRotina := {}

aAdd( aRotina, { 'Visualizar', 'VIEWDEF.CMVC_01', 0, 2, 0, NIL } ) 
aAdd( aRotina, { 'Incluir'   , 'VIEWDEF.CMVC_01', 0, 3, 0, NIL } )
aAdd( aRotina, { 'Alterar'   , 'VIEWDEF.CMVC_01', 0, 4, 0, NIL } )
aAdd( aRotina, { 'Excluir'   , 'VIEWDEF.CMVC_01', 0, 5, 0, NIL } )
aAdd( aRotina, { 'Imprimir'  , 'VIEWDEF.CMVC_01', 0, 8, 0, NIL } )
aAdd( aRotina, { 'Copiar'    , 'VIEWDEF.CMVC_01', 0, 9, 0, NIL } ) 

Return aRotina

Notou que no exemplo todas as ações chamam a função VIEWDEF.CMVC_01 ?

O Browse é preparado para entender que essa instrução significa que você vai executar a View (MVC) do fonte CMVC_01 quando aquela operação for executada, ou seja, se o seu fonte se chama Zezinho.PRW a sua chamada será VIEWDEF.ZEZINHO.

Passo 04: Model

Como já foi dito, o model é o responsável pela regra de negócio e a função ModelDef é onde o model é definido. A função ModelDef deve sempre retornar o objeto do Model.

O Model é um objeto, logo para cria-lo é necessário instanciarmos uma classe, o framework do AdvPL disponibiliza duas classes para o model, a classe FWFormModel e a classe MPFormModel.

A FWFormModel é pouco usada, ela deve ser utilizada quando sua aplicação independe totalmente de dicionário de dados e qualquer outro suporte do nível do Protheus.

A MPFormModel realiza o tratamento da função Help, cria variáveis de memória e disponibiliza funções para persistência em campos existentes no dicionário de dados, ela é utilizada em todas as aplicações do Protheus.

Para criar o model, vamos instanciar a classe MPFormModel, ela possui 5 parâmetros:

  1. cIDModel : ID do Modelo (Obrigatório). O MVC trabalha com Identificadores, todo componente de Model ou View tem um ID.
  2. bPreValidacao: Bloco de código de pré validação do modelo (Opcional)
  3. bPosValidacao: Bloco de código de pós validação do modelo (Opcional)
  4. bCommit: Bloco de persistência dos dados, é preenchido automaticamente, devendo ser preenchido somente quando se deseja alterar a persistência dos dados
  5. bCancel: Bloco de persistência dos dados, é preenchido automaticamente, devendo ser preenchido somente quando se deseja alterar a persistência dos dado

Nesse momento vamos usar apenas o primeiro parâmetro, os outros 4 ficam pra um outro artigo.

Static Function ModelDef()
Local oModel

      oModel := MPFormModel():New("MD_ALUNO")

Return oModel

 

O ID do modelo NUNCA pode ser igual ao nome da sua função principal caso a sua função seja uma User Function, pois esse ID é usado para criar os pontos de entrada da aplicação. Se a sua aplicação e seu ID tem o mesmo nome, não vai ser possível criar a User Function para os pontos de entrada.

Passo 05: View

A View é a camada responsável pela interface gráfica e interação com o seu usuário. A View também é um objeto, que deve ser definido dentro da função ViewDef e por sua vez a função deve retornar o objeto de View.

A View é uma classe e para criar o objeto devemos instanciar a classe FwFormView, o método New não recebe nenhum parâmetro.

Static Function ViewDef()
Local oView

      oView := FWFormView():New() 

Return oView

 

Associando a View com um Model

A View é somente a “casca” da aplicação, ela precisa de dados para exibir na tela, esses dados estão dentro do Model, por esse motivo uma View sempre precisa ser associada a um modelo.

Essa associação ocorre através do método SetModel, que recebe como parâmetro o objeto do Model. O objeto de model pode ser criado de duas formas:

  • Se o Model que você vai usar está definido no mesmo fonte que a sua View, simplesmente chame a função ModelDef(), que sempre retorna o objeto de Model;
  • Entretanto, se o Model que você vai usar está definido em outro fonte, use a função FWLoadModel para carregar o modelo desejado.

 

Static Function ViewDef()
Local oView
Local oModel := ModelDef()

      oView := FWFormView():New() 
      oView:SetModel(oModel)

Return oView

 

Passo 06: Criando um FormField no Model

O MVC possui vários componentes, onde cada um tem a sua responsabilidade. O Field é um componente que tem como objetivo permitir a manipulação de um registro de dado, quando criado no Model e permitir a exibição de um registro ao usuário, quando criado na View.

Não gosto de comparações, mas se ajudar, ele funciona como a Enchoice.

Criando uma Estrutura de Dados básica

O MVC trabalha com Estrutura de Dados, um componente do tipo Field, precisa de uma estrutura de dados para definir qual tabela e campos serão manipulados pelo componente. A estrutura fornece:

  • Campos
  • Gatilhos
  • Validações
  • E outros dados importantes

Como já foi dito, o MVC não depende de Dicionário de Dados, todavia é possível criar uma Estrutura de Dados baseada em um dicionário. Sempre que você vai criar uma aplicação para o Protheus é interessante utilizar essa funcionalidade, pois dessa forma você não precisa criar a estrutura “do zero”, você realiza o carregamento e se preciso altera a estrutura para atender a sua necessidade.

Para criar uma Estrutura baseada em um Dicionário é necessário usar a função FWFormStruct, ela retorna um objeto de estrutura (FWFormModelStruct) baseado em dois parâmetros que recebe:

  1. nTipo: Indica o tipo de estrutura que você quer criar, use 1 quando é uma estrutura para o Field de um Model e 2 quando é uma estrutura para o Field de uma View
  2. cAlias: Indica o nome da tabela do Dicionário de Dados que será usado como referência para a estrutura
 oStrZB2 := FWFormStruct(1, “ZB2”)

O objeto oStrZB2 conterá uma tabela com os dados, campos, gatilhos e índices da tabela ZB2 do Dicionário de Dados do Protheus.

Criando o componente Field

O componente existe na View e no Model, primeiramente criaremos no model e logo depois na View.

Agora que já sabemos como criar uma estrutura de dados para o Field, vamos criar o componente em si, para isso é necessário usar o método AddFields do componente Model, esse método recebe vários parâmetros, mas agora vamos usar apenas dois, o primeiro e o terceiro parâmetro:

  1. ID do componente Field
  2. ID do Owner, não vamos usar agora
  3. Objeto de estrutura de dados para o Field
Static Function ModelDef()
Local oModel
Local oStruZB2 := FWFormStruct(1,"ZB2")

 oModel := MPFormModel():New("MD_ALUNO") 
 oModel:addFields('MASTERZB2',,oStruZB2)
 
Return oModel

 

Passo 07: Criando um FormField no View

Na View o Field é representado por um formulário, esse formulário mostra na tela os campos presentes na estrutura de dados do Field e o componente permite que o usuário visualize e edite/inclua/visualize os dados do registro.

Criando a estrutura de dados básica

A Estrutura de Dados da View descreve os campos que serão exibidos na tela para o usuário, por esse motivo a estrutura contém informações de interface gráfica, como por exemplo:

  • Picture
  • Consulta Padrão
  • Pastas
  • Grupos

Assim como no Model podemos criar uma estrutura baseada em um Dicionário de Dados, na View isso também é possível, basta usar a função FWFormStruct passando no primeiro parâmetro o tipo 2.

oStrZB2 := FWFormStruct(2, “ZB2”)

A função FWFormStruct retornará um objeto do tipo FWFormViewStruct.

Criando o Field

Já sabemos como criar a estrutura de dados para o formulário, agora podemos criar o componente na View. A View precisa de um Model, já que toda a definição da regra da aplicação e também os dados ficam nele.

Cada formulário da View precisa estar relacionado com um componente do Model e os componentes precisam ser do mesmo tipo.  Logo se o Model tem um Field com a estrutura da tabela Alunos (ZB2), então a View que vai usar esse Model também precisa de um Field com a estrutura da mesma tabela ZB2 e precisa relacionar o Field da View com o Field do Model, esse relacionamento se dá através dos IDs dos componentes.

Para criar o Field usamos um método da View chamado AddField, que recebe alguns parâmetros, mas agora veremos os 3 primeiros:

  1. IDView: Representa a identificação que você vai dar para o seu formulário
  2. oStruct: Objeto de Estrutura de Dados do tipo FWFormViewStruct
  3. IDModel: ID do Field que está no Model
oView:AddField(cIDView,oStruct,cIDModel)

Recomendo que seja usado IDs diferentes para o componente na View e no Model, pois dessa forma é mais fácil identificar os componentes, exemplo:

oView:AddField(“FORM_ALUNO”,oStruct,”MASTERZB2”)

Nesse caso de cima, sabemos que o identificador “FORM_ALUNO” é referente ao formulário Field da View e o identificador “MASTERZB2” faz referência ao componente Field do Model.

 

Box: O componente que vai dividir a sua tela em partes

A View possui alguns componentes de formulários (como o Field que estamos vendo), mas esses componentes precisam ser alocados em painéis dentro da View, apenas cria-los não faz com que sejam mostrados na tela.

Até agora só criamos um field, mas imagine uma View onde você tenha 10 formulários, você precisa criar painéis para dividir a tela e alocar esses formulários. Esses painéis na View são representados por dois componentes, o HorizontalBox e o VerticalBox.

O componente HorizontalBox cria painéis na horizontal e o VerticalBox cria painéis na vertical, os dois componentes trabalham com percentual, você define um ID para cada painel e qual o percentual da tela que ele deve ocupar.

Logo, se você precisa exibir apenas um formulário, você precisa criar um box de 100% da tela. Se você precisa exibir dois formulários, então você cria dois boxes e a soma do percentual dos dois tem que ser 100 e assim por diante, a soma dos boxes de um mesmo tipo deve ser sempre igual a 100 por cento.

O método CreateHorizontalBox recebe vários parâmetros, mas vamos nos atentar para os dois primeiros:

  1. cIDBox : Identificação do painel
  2. nPerc: Percentual da tela que o painel deve ocupar
oModel:CreateHorizontalBox(cID,nPerc)

No momento nós já criamos o formulário e o box, agora vamos alocar o formulário no box que criamos, isso é feito através do método SetOwnerView, que recebe dois parâmetros:

  1. ID do formulário
  2. ID do box
oView:SetOwnerView(cIDFORM,cIDBOX)

 

Se seguiu tudo que eu falei, a sua ViewDef deve ficar assim:

Static Function ViewDef()
Local oModel := ModelDef()
Local oView
Local oStrZB2:= FWFormStruct(2, 'ZB2')
 
 oView := FWFormView():New()
 oView:SetModel(oModel)
 oView:AddField('FORM_ALUNO' , oStrZB2,'MASTERZB2' ) 
 oView:CreateHorizontalBox( 'BOX_FORM_ALUNO', 100)
 oView:SetOwnerView('FORM_ALUNO','BOX_FORM_ALUNO')
 
Return oView

Passo 08: Fim!

Se seguiu tudo que falei, seu Hello Word deve te ficado assim:

#Include 'Protheus.ch'
#Include 'FWMVCDEF.ch'

User Function CMVC_01()
Local oBrowse

 oBrowse := FWMBrowse():New()
 oBrowse:SetAlias('ZB2')
 oBrowse:SetDescription('Cadastro de Alunos')
 oBrowse:Activate()
Return

Static Function MenuDef()
Local aRotina := {}

aAdd( aRotina, { 'Visualizar', 'VIEWDEF.CMVC_01', 0, 2, 0, NIL } ) 
aAdd( aRotina, { 'Incluir' , 'VIEWDEF.CMVC_01', 0, 3, 0, NIL } )
aAdd( aRotina, { 'Alterar' , 'VIEWDEF.CMVC_01', 0, 4, 0, NIL } )
aAdd( aRotina, { 'Excluir' , 'VIEWDEF.CMVC_01', 0, 5, 0, NIL } )
aAdd( aRotina, { 'Imprimir' , 'VIEWDEF.CMVC_01', 0, 8, 0, NIL } )
aAdd( aRotina, { 'Copiar' , 'VIEWDEF.CMVC_01', 0, 9, 0, NIL } ) 

Return aRotina

Static Function ModelDef()
Local oModel
Local oStruZB2 := FWFormStruct(1,"ZB2")

 oModel := MPFormModel():New("MD_ALUNO") 
 oModel:addFields('MASTERZB2',,oStruZB2)
 
Return oModel

Static Function ViewDef()
Local oModel := ModelDef()
Local oView
Local oStrZB2:= FWFormStruct(2, 'ZB2')
 
 oView := FWFormView():New()
 oView:SetModel(oModel)
 oView:AddField('FORM_ALUNO' , oStrZB2,'MASTERZB2' ) 
 oView:CreateHorizontalBox( 'BOX_FORM_ALUNO', 100)
 oView:SetOwnerView('FORM_ALUNO','BOX_FORM_ALUNO')
 
Return oView

 

Compile o fonte, coloque a função no menu e execute sua primeira aplicação em MVC.

Anúncios

6 comentários em “Hello Word

  1. Oi Juliane, parabéns pelo excelente conteúdo que você preparou para nós 🙂
    Comecei a aprender Adpl a pouco tempo (mas já programo em outras linguagens) e estou adorando ler e aprender com seu blog.

    Tenho uma contribuição a fazer:
    No Passo 07 > Box, está mencionando o oModel ao invés de oView.

    Esta assim:
    oModel:CreateHorizontalBox(cID,nPerc)

    Mas deveria ser assim:
    oView:CreateHorizontalBox(cID,nPerc)

    A um pedido a fazer também rsss
    Como sou iniciante, ao começar a seguir seu post, eu compilei o fonte UPPDOM.prw e tentei chamar a User Function via campo Formulas e também definindo pelo Menu.
    Não funcionou e retornou este erro:

    “`
    THREAD ERROR ([13524], Ed, SUPORTE) 18/07/2017 12:56:41

    Alias already in use: SM0
    on MYOPENSM0(UPDDOM.PRW) 18/07/2017 09:42:01 line : 2899

    “`

    Como não consegui criar as tabelas, quando eu tento executar este hello world, retorna este erro:

    “`
    THREAD ERROR ([5280], Ed, SUPORTE) 18/07/2017 13:05:58
    Alias does not exist ZB2 on FWBRWTABLE:SETALIAS(FWBRWTABLE.PRW) 19/05/2017 09:57:52 line : 1533
    “`

    O que devo fazer?

    Curtir

    1. Oi Ednei!

      Obrigada pela contribuição, vou alterar o código.

      Sobre sua duvida, você tem que chamar a função via splash do Protheus, ao invés de chamar SiGAMDI você chama u_UPDDOM, igual como se estivesse aplicando um update do padrão.

      Abraços!

      Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s