Criando tela em MVC separando por grupos e inserindo novos botões


Segue mais um exemplo do uso de MVC, aos poucos iremos postar exemplos desde os mais simples ao mais complexo em MVC. Baseando-se no primeiro exemplo postado em Meu primeiro fonte MVC , iremos mostrar como montar uma tela onde iremos separar os campos por grupos e incluiremos um novo botão em "Ações relacionadas". mvc_exemplo2 Montaremos uma tabela simples, com 6 campos, sendo 1 do tipo virtual mvc_exemplo2_sx3_inicio

Ordem Campo Tipo Tam Contexto Propriedade Titulo F3 Inic.Padrao Inic.Browse
1 ZZ8_FILIAL C 2 R V Filial
2 ZZ8_CODIGO C 6 R A Codigo GETSX8NUM("ZZ8","ZZ8_CODIGO")
3 ZZ8_DESCR C 30 R A Descrição
4 ZZ8_USER C 6 R A Usuário SRA
5 ZZ8_NOME C 30 V V Nome IF(INCLUI,' ',POSICIONE( 'SRA', 1, XFILIAL('SRA') + ZZ8->ZZ8_USER, 'RA_NOME')) POSICIONE( 'SRA', 1, xFilial('SRA') + ZZ8->ZZ8_USER, 'RA_NOME')
6 ZZ8_BLQ C 1 R A Bloqueado? "2"
Em todos os campos vá na aba "Uso" e marque as opções "usado" e "browse". O índice deixe como ZZ8_FILIAL + ZZ8_CODIGO Detalhes do campo ZZ8_BLQ (este campo será do tipo lista)mvc_exemplo2_sx3_zz8_blq_campo mvc_exemplo2_sx3_zz8_blq_opcoes Detalhes do campo virtual ZZ8_NOME, veja como fica os inicializadores padrão e browse mvc_exemplo2_sx3_zz8_nome_campomvc_exemplo2_sx3_zz8_nome_opcoes Uma nova característica que o MVC possui para uso da interface é para um componente de formulário, fazer o agrupamento dos campos na tela. Iremos criar 3 grupos, para isso será necessário utilizar o método AddGroup
//Criando grupos
oStr1:AddGroup( 'GRUPO01', 'Descrição'		, '', 1 )
oStr1:AddGroup( 'GRUPO02', 'Funcionário'	, '', 2 )
oStr1:AddGroup( 'GRUPO03', 'Outros'		, '', 3 )
Agora iremos informar para o objeto onde os campos ficarão. Para colocar todos os campos num único grupo você pode utilizar o asterisco (*)
// Colocando todos os campos para um agrupamento'
oStr1:SetProperty( '*' , MVC_VIEW_GROUP_NUMBER, 'GRUPO01' )
ou
// Colocando alguns campos por agrupamentos'
oStr1:SetProperty( 'ZZ8_CODIGO'	, MVC_VIEW_GROUP_NUMBER, 'GRUPO01' )
oStr1:SetProperty( 'ZZ8_DESCR'	, MVC_VIEW_GROUP_NUMBER, 'GRUPO01' )

oStr1:SetProperty( 'ZZ8_USER' 	, MVC_VIEW_GROUP_NUMBER, 'GRUPO02' )
oStr1:SetProperty( 'ZZ8_NOME' 	, MVC_VIEW_GROUP_NUMBER, 'GRUPO02' )
	
oStr1:SetProperty( 'ZZ8_BLQ', MVC_VIEW_GROUP_NUMBER, 'GRUPO03' )
Agora iremos inserir um novo botão em "Ações relacionadas" Para a criação de botões adicionais na barra de botões da interface utilizamos o método AddUserButton
//Criando um botão
oView:AddUserButton( 'Novo botão', 'NOTE', {|oView| alert("Você clicou aqui")} )
Onde o "Novo botão", é o texto que será apresentado no botão, "NOTE" é o nome da imagem do RPO (apesar de não exibir, é um parametro que faz parte) que será usada para o botão e o 3º parâmetro é o bloco de código que será executado ao acionar o botão. mvc_exemplo2_novo_botao Para ficar melhor, segue o código fonte, copie e compile em seu projeto para vê-lo funcionado.
/*Importar as bibliotecas*/
#INCLUDE "PROTHEUS.CH"
#INCLUDE "FWMBROWSE.CH"
#INCLUDE "FWMVCDEF.CH"

/*Iniciando sua função*/
User Function fEXPMVC1()
	/*Declarando as variáveis que serão utilizadas*/
	Local lRet := .T.
	Local aArea := ZZ8->(GetArea())
	Private oBrowse
	Private cChaveAux := ""

	//Iniciamos a construção básica de um Browse.
	oBrowse := FWMBrowse():New()

	//Definimos a tabela que será exibida na Browse utilizando o método SetAlias
	oBrowse:SetAlias("ZZ8")

	//Definimos o título que será exibido como método SetDescription
	oBrowse:SetDescription("DESCRIÇÃO")

	//Adiciona um filtro ao browse
	oBrowse:SetFilterDefault( "" )
		
	//Ativamos a classe
	oBrowse:Activate()
	RestArea(aArea)
Return
 
//-------------------------------------------------------------------
// Montar o menu Funcional
//-------------------------------------------------------------------
Static Function MenuDef()
	Local aRotina := {}
	ADD OPTION aRotina TITLE "Pesquisar"  	ACTION 'PesqBrw' 				OPERATION 1 ACCESS 0
	ADD OPTION aRotina TITLE "Visualizar" 	ACTION "VIEWDEF.fEXPMVC1"	OPERATION 2 ACCESS 0
	ADD OPTION aRotina TITLE "Incluir"    	ACTION "VIEWDEF.fEXPMVC1" 	OPERATION 3 ACCESS 0
	ADD OPTION aRotina TITLE "Alterar"    	ACTION "VIEWDEF.fEXPMVC1" 	OPERATION 4 ACCESS 0
	ADD OPTION aRotina TITLE "Excluir"    	ACTION "VIEWDEF.fEXPMVC1" 	OPERATION 5 ACCESS 0
	ADD OPTION aRotina TITLE "Imprimir" 	ACTION "VIEWDEF.fEXPMVC1" 	OPERATION 8 ACCESS 0
	ADD OPTION aRotina TITLE "Copiar" 		ACTION "VIEWDEF.fEXPMVC1" 	OPERATION 9 ACCESS 0
Return aRotina
 
Static Function ViewDef()
	Local oView
	Local oModel 		:= ModelDef()
	Local bAvalCampo 	:= {|cCampo| AllTrim(cCampo)+"|" $ "ZZ8_CODIGO|ZZ8_DESCR|ZZ8_NOME|"}
	Local oStr1		:= NIL
	Local nOperation := oModel:GetOperation()
	
	oStr1		:= FWFormStruct(2, 'ZZ8')

	// Cria o objeto de View
	oView := FWFormView():New()
	oView:Refresh()
	
	// Define qual o Modelo de dados será utilizado
	oView:SetModel(oModel)
	
	//Adiciona no nosso View um controle do tipo FormFields(antiga enchoice)
	oView:AddField('Formulario' , oStr1,'CamposZZ8' )

    //Remove os campos que não irão aparecer	
	//oStr1:RemoveField( 'ZZ8_BLQ' )
	
	// Criar um "box" horizontal para receber algum elemento da view
	oView:CreateHorizontalBox( 'PAI', 100)
	
	// Relaciona o ID da View com o "box" para exibicao
	oView:SetOwnerView('Formulario','PAI')
	oView:EnableTitleView('Formulario' , 'Descricao' )
	oView:SetViewProperty('Formulario' , 'SETCOLUMNSEPARATOR', {10})
	
	//Criando grupos
	oStr1:AddGroup( 'GRUPO01', 'Descrição'		, '', 1 )
	oStr1:AddGroup( 'GRUPO02', 'Funcionário'	, '', 2 )
	oStr1:AddGroup( 'GRUPO03', 'Outros'		, '', 3 )
	
	// Colocando alguns campos por agrupamentos'
	oStr1:SetProperty( 'ZZ8_CODIGO'	, MVC_VIEW_GROUP_NUMBER, 'GRUPO01' )
	oStr1:SetProperty( 'ZZ8_DESCR'	, MVC_VIEW_GROUP_NUMBER, 'GRUPO01' )

	oStr1:SetProperty( 'ZZ8_USER' 	, MVC_VIEW_GROUP_NUMBER, 'GRUPO02' )
	oStr1:SetProperty( 'ZZ8_NOME' 	, MVC_VIEW_GROUP_NUMBER, 'GRUPO02' )
		
	oStr1:SetProperty( 'ZZ8_BLQ', MVC_VIEW_GROUP_NUMBER, 'GRUPO03' )
	
	
	//Criando um botão
	oView:AddUserButton( 'Novo botão', 'CLIPS', {|oView| alert("Você clicou aqui")} )

	//Força o fechamento da janela na confirmação
	oView:SetCloseOnOk({||.T.})

	
Return oView
 
Static Function ModelDef()
	Local oModel
	Local oStr1:= FWFormStruct( 1, 'ZZ8', /*bAvalCampo*/,/*lViewUsado*/ ) // Construção de uma estrutura de dados
	
	//Cria o objeto do Modelo de Dados
   //Irie usar uma função fEXPMVC1V que será acionada quando eu clicar no botão "Confirmar"
	oModel := MPFormModel():New('Descricao', /*bPreValidacao*/, { | oModel | fEXPMVC1V( oModel ) } , /*{ | oMdl | fEXPMVC1C( oMdl ) }*/ ,, /*bCancel*/ )
	oModel:SetDescription('Descrição')
	
	//Abaixo irei iniciar o campo X5_TABELA com o conteudo da sub-tabela
	oStr1:SetProperty('ZZ8_CODIGO' , MODEL_FIELD_INIT,{|| GetSXENum("ZZ8","ZZ8_CODIGO")} )

    //Abaixo irei bloquear/liberar os campos para edição
	oStr1:SetProperty('ZZ8_CODIGO' , MODEL_FIELD_WHEN,{|| .F. })
	oStr1:SetProperty('ZZ8_NOME'   , MODEL_FIELD_WHEN,{|| .F. })

	// Adiciona ao modelo uma estrutura de formulário de edição por campo
	oModel:addFields('CamposZZ8',,oStr1,{|oModel|fEXPMVC1T(oModel)},,)
	
	//Define a chave primaria utilizada pelo modelo
	oModel:SetPrimaryKey({'ZZ8_CODIGO', 'ZZ8_DESCR', 'ZZ8_USER' })
	
	// Adiciona a descricao do Componente do Modelo de Dados
	oModel:getModel('CamposZZ8'):SetDescription('TabelaZZ8')
	
Return oModel
 
//Esta função será executada no inicio do carregamento da tela, neste exemplo irei
//apenas armazenar numa variável o conteudo de um campo
Static Function fEXPMVC1T( oModel )
	Local lRet      := .T.
	Local oModelZZ8 := oModel:GetModel( 'CamposZZ8' )
	
	cChaveAux := ZZ8->ZZ8_CODIGO

Return(lRet)
 
//-------------------------------------------------------------------
// Validações ao salvar registro
// Input: Model
// Retorno: Se erros foram gerados ou não
//-------------------------------------------------------------------
Static Function fEXPMVC1V( oModel )
	Local lRet      := .T.
	Local oModelZZ8 := oModel:GetModel( 'CamposZZ8' )
	Local nOpc      := oModel:GetOperation()
	Local aArea     := GetArea()

	//Capturar o conteudo dos campos
	Local cChave	:= oModelZZ8:GetValue('ZZ8_CODIGO')
	Local cTabela	:= oModelZZ8:GetValue('ZZ8_DESCR')
	Local cDescri	:= oModelZZ8:GetValue('ZZ8_USER')
	Local cBlq		:= oModelZZ8:GetValue('ZZ8_BLQ')
	
	Begin Transaction
		
		if nOpc == 3 .or. nOpc == 4
			
			dbSelectArea("ZZ8")
			ZZ8->(dbSetOrder(1))
			ZZ8->(dbGoTop())
			If(ZZ8->(dbSeek(xFilial("ZZ8")+cChave)))
				if cChaveAux != cChave
					SFCMsgErro("A chave "+Alltrim(cChave)+" ja foi informada!","fEXPMVC1")
					lRet := .F.
				Endif
			Endif

			if Empty(cChave)
				SFCMsgErro("O campo chave é obrigatório!","fEXPMVC1")
				lRet := .F.
			Endif
			
			if Empty(cDescri)
				SFCMsgErro("O campo descrição é obrigatório!","fEXPMVC1")
				lRet := .F.
			Endif
			
		Endif
		
		if !lRet
			DisarmTransaction()
		Endif
		
	End Transaction
	
	RestArea(aArea)
	
	FwModelActive( oModel, .T. )
	
Return lRet