Vídeo Aula – AdvPL 028 – Abas em MVC

Olá pessoal…

Na vídeo aula de hoje, vou mostrar como fazer abas (folders) em MVC.

Abaixo o código do exemplo 1 (Pai e Filhos):

//Bibliotecas
#Include 'Protheus.ch'
#Include 'FWMVCDef.ch'
 
//Variáveis Estáticas
Static cTitulo := "Grp. Produtos (Abas)"
 
/*/{Protheus.doc} zAba1
Exemplo de rotina com multiplas abas em MVC
@author Atilio
@since 25/07/2017
@version 1.0
	@return Nil, Função não tem retorno
	@example
	u_zAba1()
/*/
 
User Function zAba1()
	Local aArea   := GetArea()
	Local oBrowse
	Local cFunBkp := FunName()
	
	SetFunName("zAba1")
	
	//Instânciando FWMBrowse
	oBrowse := FWMBrowse():New()
	oBrowse:SetAlias("SBM")
	oBrowse:SetDescription(cTitulo)
	oBrowse:Activate()
	
	SetFunName(cFunBkp)
	RestArea(aArea)
Return Nil

/*---------------------------------------------------------------------*
 | Func:  MenuDef                                                      |
 | Desc:  Criação do menu MVC                                          |
 *---------------------------------------------------------------------*/
 
Static Function MenuDef()
	Local aRot := {}
	
	//Adicionando opções
	ADD OPTION aRot TITLE 'Visualizar' ACTION 'VIEWDEF.zAba1' OPERATION MODEL_OPERATION_VIEW   ACCESS 0 //OPERATION 1
Return aRot
 
/*---------------------------------------------------------------------*
 | Func:  ModelDef                                                     |
 | Desc:  Criação do modelo de dados MVC                               |
 *---------------------------------------------------------------------*/
 
Static Function ModelDef()
	Local oModel     := Nil
	Local oStPai     := FWFormStruct(1, 'SBM')
	Local oStFilho1  := FWFormStruct(1, 'SB1')
	Local oStFilho2  := FWFormStruct(1, 'SB1')
	Local aRelFilho1 := {}
	Local aRelFilho2 := {}
	
	//Criando o modelo
	oModel := MPFormModel():New('zAba1M')
	oModel:AddFields('SBM_MASTER', /*cOwner*/, oStPai)
	
	//Criando as grids dos filhos
	oModel:AddGrid('SB1_FILHO1', 'SBM_MASTER', oStFilho1)
	oModel:AddGrid('SB1_FILHO2', 'SBM_MASTER', oStFilho2)
	
	//Criando os relacionamentos dos pais e filhos
	aAdd(aRelFilho1, {'B1_FILIAL', 'BM_FILIAL'})
	aAdd(aRelFilho1, {'B1_GRUPO',  'BM_GRUPO'})
	aAdd(aRelFilho1, {'B1_LOCPAD', '00'})
	aAdd(aRelFilho2, {'B1_FILIAL', 'BM_FILIAL'})
	aAdd(aRelFilho2, {'B1_GRUPO',  'BM_GRUPO'})
	aAdd(aRelFilho2, {'B1_LOCPAD', '01'})
	
	//Criando o relacionamento do Filho 1
	oModel:SetRelation('SB1_FILHO1', aRelFilho1, SB1->(IndexKey(1)))
	oModel:GetModel('SB1_FILHO1'):SetUniqueLine({"B1_FILIAL","B1_COD"})
	
	//Criando o relacionamento do Filho 2
	oModel:SetRelation('SB1_FILHO2', aRelFilho2, SB1->(IndexKey(1)))
	oModel:GetModel('SB1_FILHO2'):SetUniqueLine({"B1_FILIAL","B1_COD"})
	
	//Finaliznado a criação do Model
	oModel:SetPrimaryKey({})
	oModel:SetDescription("Grupo de Produtos - com Abas")
	oModel:GetModel('SBM_MASTER'):SetDescription('Modelo Grupo')
	oModel:GetModel('SB1_FILHO1'):SetDescription('Modelo Prod. Arm. 00')
	oModel:GetModel('SB1_FILHO2'):SetDescription('Modelo Prod. Arm. 01')
Return oModel
 
/*---------------------------------------------------------------------*
 | Func:  ViewDef                                                      |
 | Desc:  Criação da visão MVC                                         |
 *---------------------------------------------------------------------*/
 
Static Function ViewDef()
	Local oView     := Nil
	Local oModel    := FWLoadModel('zAba1')
	Local oStPai    := FWFormStruct(2, 'SBM')
	Local oStFilho1 := FWFormStruct(2, 'SB1')
	Local oStFilho2 := FWFormStruct(2, 'SB1')
	
	//Criando a View
	oView := FWFormView():New()
	oView:SetModel(oModel)
	
	//Adicionando os campos do cabeçalho
	oView:AddField('VIEW_SBM', oStPai, 'SBM_MASTER')
	
	//Grids dos filhos
	oView:AddGrid('VIEW_FILHO1', oStFilho1, 'SB1_FILHO1')
	oView:AddGrid('VIEW_FILHO2', oStFilho2, 'SB1_FILHO2')
	
	//Setando o dimensionamento de tamanho
	oView:CreateHorizontalBox('SUPERIOR', 30)
	oView:CreateHorizontalBox('INFERIOR', 70)
	
	//Criando a folder dos produtos (filhos)
	oView:CreateFolder('PASTA_FILHOS', 'INFERIOR')
	oView:AddSheet('PASTA_FILHOS', 'ABA_FILHO01', "Armazém 00")
	oView:AddSheet('PASTA_FILHOS', 'ABA_FILHO02', "Armazém 01")
	
	//Criando os vinculos onde serão mostrado os dados
	oView:CreateHorizontalBox('ITENS_FILHO01', 100,,, 'PASTA_FILHOS', 'ABA_FILHO01' )
	oView:CreateHorizontalBox('ITENS_FILHO02', 100,,, 'PASTA_FILHOS', 'ABA_FILHO02' )
	
	//Amarrando a view com as box
	oView:SetOwnerView('VIEW_SBM',    'SUPERIOR')
	oView:SetOwnerView('VIEW_FILHO1', 'ITENS_FILHO01')
	oView:SetOwnerView('VIEW_FILHO2', 'ITENS_FILHO02')
Return oView

Abaixo o código do exemplo 2 (Pai, Filhos e Netos):

//Bibliotecas
#Include 'Protheus.ch'
#Include 'FWMVCDef.ch'
 
//Variáveis Estáticas
Static cTitulo := "Grp. Produtos (Abas)"
 
/*/{Protheus.doc} zAba2
Exemplo de rotina com multiplas abas em MVC
@author Atilio
@since 25/07/2017
@version 1.0
	@return Nil, Função não tem retorno
	@example
	u_zAba2()
/*/
 
User Function zAba2()
	Local aArea   := GetArea()
	Local oBrowse
	Local cFunBkp := FunName()
	
	SetFunName("zAba2")
	
	//Instânciando FWMBrowse
	oBrowse := FWMBrowse():New()
	oBrowse:SetAlias("SBM")
	oBrowse:SetDescription(cTitulo)
	oBrowse:Activate()
	
	SetFunName(cFunBkp)
	RestArea(aArea)
Return Nil

/*---------------------------------------------------------------------*
 | Func:  MenuDef                                                      |
 | Desc:  Criação do menu MVC                                          |
 *---------------------------------------------------------------------*/
 
Static Function MenuDef()
	Local aRot := {}
	
	//Adicionando opções
	ADD OPTION aRot TITLE 'Visualizar' ACTION 'VIEWDEF.zAba2' OPERATION MODEL_OPERATION_VIEW ACCESS 0
Return aRot
 
/*---------------------------------------------------------------------*
 | Func:  ModelDef                                                     |
 | Desc:  Criação do modelo de dados MVC                               |
 *---------------------------------------------------------------------*/
 
Static Function ModelDef()
	Local oModel     := Nil
	Local oStPai     := FWFormStruct(1, 'SBM')
	Local oStFilho1  := FWFormStruct(1, 'SB1')
	Local oStFilho2  := FWFormStruct(1, 'SB1')
	Local oStNeto1a  := FWFormStruct(1, 'SD1')
	Local oStNeto1b  := FWFormStruct(1, 'SC7')
	Local oStNeto2a  := FWFormStruct(1, 'SD1')
	Local oStNeto2b  := FWFormStruct(1, 'SC7')
	Local aRelFilho1 := {}
	Local aRelFilho2 := {}
	Local aRelNeto1a := {}
	Local aRelNeto1b := {}
	Local aRelNeto2a := {}
	Local aRelNeto2b := {}
	
	//Criando o modelo
	oModel := MPFormModel():New('zAba2M')
	oModel:AddFields('SBM_MASTER', /*cOwner*/, oStPai)
	
	//Criando as grids dos filhos
	oModel:AddGrid('SB1_FILHO1', 'SBM_MASTER', oStFilho1)
	oModel:AddGrid('SB1_FILHO2', 'SBM_MASTER', oStFilho2)
	
	//Criando as grids dos netos
	oModel:AddGrid('SD1_NETO1A', 'SB1_FILHO1', oStNeto1a)
	oModel:AddGrid('SC7_NETO1B', 'SB1_FILHO1', oStNeto1b)
	oModel:AddGrid('SD1_NETO2A', 'SB1_FILHO2', oStNeto2a)
	oModel:AddGrid('SC7_NETO2B', 'SB1_FILHO2', oStNeto2b)
	
	//Criando os relacionamentos dos pais e filhos
	aAdd(aRelFilho1, {'B1_GRUPO',  'BM_GRUPO'})
	aAdd(aRelFilho1, {'B1_LOCPAD', '00'})
	aAdd(aRelFilho2, {'B1_GRUPO',  'BM_GRUPO'})
	aAdd(aRelFilho2, {'B1_LOCPAD', '01'})
	
	//Criando os relacionamentos dos netos com os filhos
	aAdd(aRelNeto1a, {'D1_COD',     "oModel:GetModel('SB1_FILHO1'):GetValue('B1_COD')"})
	aAdd(aRelNeto1a, {'D1_LOCAL',   "oModel:GetModel('SB1_FILHO1'):GetValue('B1_LOCPAD')"})
	aAdd(aRelNeto1b, {'C7_PRODUTO', "oModel:GetModel('SB1_FILHO1'):GetValue('B1_COD')"})
	aAdd(aRelNeto1b, {'C7_LOCAL',   "oModel:GetModel('SB1_FILHO1'):GetValue('B1_LOCPAD')"})
	aAdd(aRelNeto2a, {'D1_COD',     "oModel:GetModel('SB1_FILHO2'):GetValue('B1_COD')"})
	aAdd(aRelNeto2a, {'D1_LOCAL',   "oModel:GetModel('SB1_FILHO2'):GetValue('B1_LOCPAD')"})
	aAdd(aRelNeto2b, {'C7_PRODUTO', "oModel:GetModel('SB1_FILHO2'):GetValue('B1_COD')"})
	aAdd(aRelNeto2b, {'C7_LOCAL',   "oModel:GetModel('SB1_FILHO2'):GetValue('B1_LOCPAD')"})
	
	//Criando o relacionamento do Filho 1 - Produtos do Armazém 00
	oModel:SetRelation('SB1_FILHO1', aRelFilho1, SB1->(IndexKey(1)))
	oModel:GetModel('SB1_FILHO1'):SetUniqueLine({"B1_FILIAL", "B1_COD"})
	
	//Criando o relacionamento dos netos do Filho 1
	oModel:SetRelation('SD1_NETO1A', aRelNeto1a, SD1->(IndexKey(1)))
	oModel:GetModel('SD1_NETO1A'):SetUniqueLine({"D1_FILIAL", "D1_DOC", "D1_SERIE", "D1_ITEM", "D1_COD"})
	oModel:SetRelation('SC7_NETO1B', aRelNeto1b, SC7->(IndexKey(1)))
	oModel:GetModel('SC7_NETO1B'):SetUniqueLine({"C7_FILIAL", "C7_ITEM", "C7_PRODUTO"})
	
	//Criando o relacionamento do Filho 2 - Produtos do Armazém 01
	oModel:SetRelation('SB1_FILHO2', aRelFilho2, SB1->(IndexKey(1)))
	oModel:GetModel('SB1_FILHO2'):SetUniqueLine({"B1_FILIAL", "B1_COD"})
	
	//Criando o relacionamento dos netos do Filho 2
	oModel:SetRelation('SD1_NETO2A', aRelNeto2a, SD1->(IndexKey(1)))
	oModel:GetModel('SD1_NETO2A'):SetUniqueLine({"D1_FILIAL", "D1_DOC", "D1_SERIE", "D1_ITEM", "D1_COD"})
	oModel:SetRelation('SC7_NETO2B', aRelNeto2b, SC7->(IndexKey(1)))
	oModel:GetModel('SC7_NETO2B'):SetUniqueLine({"C7_FILIAL", "C7_ITEM", "C7_PRODUTO"})
	
	//Finalizando a criação do Model
	oModel:SetPrimaryKey({})
	oModel:SetDescription("Grupo de Produtos - com Abas")
	oModel:GetModel('SBM_MASTER'):SetDescription('Modelo Grupo')
	oModel:GetModel('SB1_FILHO1'):SetDescription('Modelo Prod. Arm. 00')
	oModel:GetModel('SB1_FILHO2'):SetDescription('Modelo Prod. Arm. 01')
Return oModel
 
/*---------------------------------------------------------------------*
 | Func:  ViewDef                                                      |
 | Desc:  Criação da visão MVC                                         |
 *---------------------------------------------------------------------*/
 
Static Function ViewDef()
	Local oView     := Nil
	Local oModel    := FWLoadModel('zAba2')
	Local oStPai    := FWFormStruct(2, 'SBM')
	Local oStFilho1 := FWFormStruct(2, 'SB1')
	Local oStFilho2 := FWFormStruct(2, 'SB1')
	Local oStNeto1a := FWFormStruct(2, 'SD1')
	Local oStNeto1b := FWFormStruct(2, 'SC7')
	Local oStNeto2a := FWFormStruct(2, 'SD1')
	Local oStNeto2b := FWFormStruct(2, 'SC7')
	Local nAtual    := 0
	Local aStrutSB1 := SB1->(DbStruct())
	Local aStrutSD1 := SD1->(DbStruct())
	Local aStrutSC7 := SC7->(DbStruct())
	
	//Criando a View
	oView := FWFormView():New()
	oView:SetModel(oModel)
	
	//Adicionando os campos do cabeçalho
	oView:AddField('VIEW_SBM', oStPai, 'SBM_MASTER')
	
	//Grids dos filhos
	oView:AddGrid('VIEW_FILHO1', oStFilho1, 'SB1_FILHO1')
	oView:AddGrid('VIEW_FILHO2', oStFilho2, 'SB1_FILHO2')
	
	//Grid dos netos
	oView:AddGrid('VIEW_NETO1A', oStNeto1a, 'SD1_NETO1A')
	oView:AddGrid('VIEW_NETO1B', oStNeto1b, 'SC7_NETO1B')
	oView:AddGrid('VIEW_NETO2A', oStNeto2a, 'SD1_NETO2A')
	oView:AddGrid('VIEW_NETO2B', oStNeto2b, 'SC7_NETO2B')
	
	//Setando o dimensionamento de tamanho
	oView:CreateHorizontalBox('SUPERIOR', 30)
	oView:CreateHorizontalBox('INFERIOR', 70)
	
	//Criando a folder dos produtos (filhos)
	oView:CreateFolder('PASTA_FILHOS', 'INFERIOR')
	oView:AddSheet('PASTA_FILHOS', 'ABA_FILHO01', "Armazém 00")
	oView:AddSheet('PASTA_FILHOS', 'ABA_FILHO02', "Armazém 01")
	
	//Cria as caixas onde serão mostrados os dados dos filhos
	oView:CreateHorizontalBox('ITENS_FILHO01', 050,,, 'PASTA_FILHOS', 'ABA_FILHO01' )
	oView:CreateHorizontalBox('ITENS_FILHO02', 050,,, 'PASTA_FILHOS', 'ABA_FILHO02' )
	
	//Criando a folder dos pedidos (netos do Filho 1)
	oView:CreateHorizontalBox('NETOS_FILHO01', 050,,, 'PASTA_FILHOS', 'ABA_FILHO01' )
	oView:CreateFolder('PASTA_NETO1', 'NETOS_FILHO01')
	oView:AddSheet('PASTA_NETO1', 'ABA_NETO1A', "Entradas")
	oView:AddSheet('PASTA_NETO1', 'ABA_NETO1B', "Compras")
	
	//Cria as caixas onde serão mostrados os dados dos netos do Filho 1
	oView:CreateHorizontalBox('ITENS_NETO1A', 100,,, 'PASTA_NETO1', 'ABA_NETO1A' )
	oView:CreateHorizontalBox('ITENS_NETO1B', 100,,, 'PASTA_NETO1', 'ABA_NETO1B' )
	
	//Criando a folder dos pedidos (netos do Filho 2)
	oView:CreateHorizontalBox('NETOS_FILHO02', 050,,, 'PASTA_FILHOS', 'ABA_FILHO02' )
	oView:CreateFolder('PASTA_NETO2', 'NETOS_FILHO02')
	oView:AddSheet('PASTA_NETO2', 'ABA_NETO2A', "Entradas")
	oView:AddSheet('PASTA_NETO2', 'ABA_NETO2B', "Compras")
	
	//Cria as caixas onde serão mostrados os dados dos netos do Filho 2
	oView:CreateHorizontalBox('ITENS_NETO2A', 100,,, 'PASTA_NETO2', 'ABA_NETO2A' )
	oView:CreateHorizontalBox('ITENS_NETO2B', 100,,, 'PASTA_NETO2', 'ABA_NETO2B' )
	
	//Amarrando a view com as box
	oView:SetOwnerView('VIEW_SBM',    'SUPERIOR')
	oView:SetOwnerView('VIEW_FILHO1', 'ITENS_FILHO01')
	oView:SetOwnerView('VIEW_FILHO2', 'ITENS_FILHO02')
	oView:SetOwnerView('VIEW_NETO1A', 'ITENS_NETO1A')
	oView:SetOwnerView('VIEW_NETO1B', 'ITENS_NETO1B')
	oView:SetOwnerView('VIEW_NETO2A', 'ITENS_NETO2A')
	oView:SetOwnerView('VIEW_NETO2B', 'ITENS_NETO2B')
	
	//Retira campos da SB1
	For nAtual := 1 To Len(aStrutSB1)
		If ! Alltrim(aStrutSB1[nAtual][01]) $ "B1_COD;B1_DESC;"
			oStFilho1:RemoveField(aStrutSB1[nAtual][01])
			
			oStFilho2:RemoveField(aStrutSB1[nAtual][01])
		EndIf
	Next
	
	//Retira campos da SD1
	For nAtual := 1 To Len(aStrutSD1)
		If ! Alltrim(aStrutSD1[nAtual][01]) $ "D1_FILIAL;D1_DOC;D1_ITEM;D1_QUANT;D1_VUNIT;D1_TOTAL;D1_TES;D1_FORNECE;"
			oStNeto1a:RemoveField(aStrutSD1[nAtual][01])
			
			oStNeto2a:RemoveField(aStrutSD1[nAtual][01])
		EndIf
	Next
	
	//Retira campos da SC7
	For nAtual := 1 To Len(aStrutSC7)
		If ! Alltrim(aStrutSC7[nAtual][01]) $ "C7_FILIAL;C7_NUM;C7_ITEM;C7_QUANT;C7_PRECO;C7_TOTAL;C7_TES;C7_FORNECE;"
			oStNeto1b:RemoveField(aStrutSC7[nAtual][01])
			
			oStNeto2b:RemoveField(aStrutSC7[nAtual][01])
		EndIf
	Next
	
Return oView

Bom pessoal, por hoje é só.
Um grande abraço e até a próxima.

Dan (Daniel Atilio)
Cristão de ramificação protestante. Especialista em Engenharia de Software pela FIB, graduado em Banco de Dados pela FATEC Bauru e técnico em informática pelo CTI da Unesp. Entusiasta de soluções Open Source e blogueiro nas horas vagas. Autor e mantenedor do portal Terminal de Informação.

11 Responses

  1. Felipe B disse:

    No meu não está carregando o botão de vizualizar

  2. Fabrício Stefanini disse:

    Arrebentou nesse vídeo hein! Muito bom!

  3. GERALDO disse:

    Opa eu aqui de novo , Legal seus posts sempre dando um help aqui . so uma duvido estas abas tazem uma grid ate consegui trazer minha SZX mas tem como trazer ela sem ser Grip e sim como cabecalho de cadastro como na Principal ?

  4. Marcio Medeiros disse:

    Obrigado pelos seus videos, são de muita valia! Ajudam demais.
    Pode me tirar uma duvida, por favor? Vi que voce so colocou a opção de visualizar, porém, em meu caso, preciso incluir e alterar tambem e ao tentar salvar a inclusão ou alteração, ele da errorlog e percebi que é por causa desse relacionamento entre um campo e um valor:

    oView:AddSheet(‘PASTA_FILHOS’, ‘ABA_FILHO01’, “Armazém 00”)
    oView:AddSheet(‘PASTA_FILHOS’, ‘ABA_FILHO02’, “Armazém 01”)

    Existe alguma forma de contornar esse problema?

    Obrigado

  5. Marcio Medeiros disse:

    Mencionei a parte errada do fonte:

    //Criando os relacionamentos dos pais e filhos
    aAdd(aRelFilho1, {‘B1_FILIAL’, ‘BM_FILIAL’})
    aAdd(aRelFilho1, {‘B1_GRUPO’, ‘BM_GRUPO’})
    aAdd(aRelFilho1, {‘B1_LOCPAD’, ’00’})
    aAdd(aRelFilho2, {‘B1_FILIAL’, ‘BM_FILIAL’})
    aAdd(aRelFilho2, {‘B1_GRUPO’, ‘BM_GRUPO’})
    aAdd(aRelFilho2, {‘B1_LOCPAD’, ’01’})

    //Criando o relacionamento do Filho 1
    oModel:SetRelation(‘SB1_FILHO1’, aRelFilho1, SB1->(IndexKey(1)))
    oModel:GetModel(‘SB1_FILHO1’):SetUniqueLine({“B1_FILIAL”,”B1_COD”})

    //Criando o relacionamento do Filho 2
    oModel:SetRelation(‘SB1_FILHO2’, aRelFilho2, SB1->(IndexKey(1)))
    oModel:GetModel(‘SB1_FILHO2’):SetUniqueLine({“B1_FILIAL”,”B1_COD”})

    • Boa noite Márcio, obrigado pelo feedback jovem.
      Então, como nesse caso, ele usa a mesma tabela em vários lugares diferentes, pode ser que dê problema mesmo.
      O ideal seria você interceptar e fazer seu Commit de operação.
      O único problema é que você teria que fazer manualmente os Reclocks.
      Agora se forem tabelas diferentes em cada aba ou cada cenário, ai acho que o padrão atenderia.
      Grande abraço.

  6. Alexandre Antunes de Lima disse:

    Boa tarde, vi seu artigo muito bom, uma duvida, como faço para poder alterar somente a grid dos netos

    • Bom dia Alexandre, tudo bem? Obrigado pelo feedback.
      Não sei se entendi muito bem a pergunta, mas você quer deixar a grid do filho e o pai, ambos sem alteração? Liberar apenas a parte do neto?
      Se sim, você pode tentar usar o método SetOnlyView, deixando o pai e o filho como .T. e o neto sem precisar alterar, dentro da sua ModelDef, exemplo:
      oModel:GetModel(“ZD2MASTER”):SetOnlyView(.T.)

      Caso você seja um assinante premium, nos chame no WhatsApp, tem um exemplo que irá ao ar no dia 03/04/2023, ai te mandamos o fonte para você dar uma olhada.
      Abraços.

Deixe uma resposta para Alexandre Antunes de LimaCancelar resposta

Terminal de Informação