Criando um janela de multiplas opções para retornar o resultado em um campo


Vemos isso normalmente nos módulos de Recursos Humanos, a seleção de multiplas opções onde o resultado das seleções vão para um campo. Abaixo irei mostrar como usar em uma consulta padrão de um campo e o conteúdo que irá aparecer na janela de seleção trazendo as opções de uma tabela SX5 ou de um array. No Configurador, vá em Consulta Padrão, Selecione o tipo de consulta específica, de um nome para a sua consulta e clique em Avançar. Para o exemplo em questão, na próxima tela, selecione a tabela SX5, em expressão chame a função que iremos criar e neste caso é a FMULTIOP, como parâmetro iremos colocar no nome da tabela YL - Código EDI. Poderia ser qualquer outra tabela, em retorno, teremos que dar um nome, mas para a nossa consulta não será necessário, mas como é um campo obrigatório coloque uma variavel qualquer e clique em Finalizar. Abra a tabela SXB no APSDU e remova a variável do retorno, localize o campo XB_TIPO = 5, vá no campo XB_CONTEM  e remova o conteúdo. No Configurador ou APSDU, vá no campo que desejar e informe o nome de sua consulta padrão.

Nota: A quantidade de registros selecionados dependerá do tamanho do campo que irá receber, então se o campo é de tamanho 6, apenas 6 registros serão selecionados. Para, retornar apenas um registro, informe no parâmetro l1Elem como verdadeiro (.T.)
Exemplo: U_FMULTIOP('YL','CODIGO EDI',.T.) Trazendo opções de uma tabela SX5:
//U_FMULTIOP('05')

User Function FMULTIOP(cTabela,cTitulo,l1Elem,lTipoRet)
	//Exemplo extraído da função GPEXFUNW, mas com pequenas modificações
	
	Local MvPar
	Local MvParDef:=""	
	Private aCat:={}
	
	Default cTitulo:=""		//O titulo não é obrigatório pois pode ser pegar o titulo da tabela SX5
	Default lTipoRet := .T.
	
	If(Empty(cTabela))
		MsgStop("Informe a tabela a ser pesquisada na SX5!"+CRLF+CRLF+"Avise ao Administrador do sistema. Função: FMULTIOP()","ERRO")
		Return
	Endif
	
	l1Elem := If (l1Elem = Nil , .F. , .T.)
	
	cAlias := Alias() // Salva Alias Anterior
	
	IF lTipoRet
		MvPar:=&(Alltrim(ReadVar()))	// Carrega Nome da Variavel do Get em Questao
		mvRet:=Alltrim(ReadVar())		// Iguala Nome da Variavel ao Nome variavel de Retorno
	EndIF
	
	dbSelectArea("SX5")
	
	If dbSeek(xFilial("SX5")+"00"+cTabela)
	   cTitulo := Alltrim(Left(X5Descri(),20))
	Endif
	
	If dbSeek(xFilial("SX5")+cTabela)
		CursorWait()
			aCat := {}
			While SX5->(!Eof()) .AND. SX5->X5_FILIAL == XFilial("SX5") .AND. SX5->X5_Tabela == cTabela
				Aadd(aCat,Left(SX5->X5_Chave,1) + " - " + Alltrim(X5Descri()))
				MvParDef+=Left(SX5->X5_Chave,1)
				dbSkip()
			Enddo
		CursorArrow()
	Else
		Help('',1,'FMULTIOP',,'As opções não foram inseridas!',1,0)
	Endif
	
	IF lTipoRet

		IF f_Opcoes(@MvPar,cTitulo,aCat,MvParDef,12,49,l1Elem)  // Chama funcao f_Opcoes (padrão Protheus)
			&MvRet := mvpar										 // Devolve Resultado
		EndIF
	EndIF
	
	dbSelectArea(cAlias) // Retorna Alias	
Return( IF( lTipoRet , .T. , MvParDef ) )
Sintaxe da função f_Opcoes()
Function f_Opcoes(	uVarRet			,;	//Variavel de Retorno
			cTitulo			,;	//Titulo da Coluna com as opcoes
			aOpcoes			,;	//Opcoes de Escolha (Array de Opcoes)
			cOpcoes			,;	//String de Opcoes para Retorno
			nLin1			,;	//Nao Utilizado
			nCol1			,;	//Nao Utilizado
			l1Elem			,;	//Se a Selecao sera de apenas 1 Elemento por vez
			nTam			,;	//Tamanho da Chave
			nElemRet		,;	//No maximo de elementos na variavel de retorno
			lMultSelect		,;	//Inclui Botoes para Selecao de Multiplos Itens
			lComboBox		,;	//Se as opcoes serao montadas a partir de ComboBox de Campo ( X3_CBOX )
			cCampo			,;	//Qual o Campo para a Montagem do aOpcoes
			lNotOrdena		,;	//Nao Permite a Ordenacao
			lNotPesq		,;	//Nao Permite a Pesquisa	
			lForceRetArr		,;	//Forca o Retorno Como Array
			cF3			 ;	//Consulta F3	
		  )
  Continua página 2 Trazendo opções de um ARRAY: Na função que criei, passo como parâmetro o titulo e as opções. As opções serão incluídas dentro de um array. A quantidade de opções incluindo direto como parâmetro irá depender do espaço disponível no campo XB_CONTEM, para poucas opções não é necessário incluí-las no fonte, com isso fica mais dinâmico. Note na imagem acima que o quadro "Máx.Elem.p/Seleção" está com 1, neste caso, determinei que apenas 1 registro será selecionado. O parâmetro responsável para isso é o l1Elem, se ele estiver como verdadeiro (.T.), apenas um registro será selecionado por vez.
//U_FSELARRA("Tipo de CT-e",x3CboxToArray("F1_TPCTE")[1])                                                                                                                                                                                   
//A função x3CboxToArray irá buscar o conteudo do campo X3_CBOX do campo F1_TPCTE e converterá em um array
//OU
//U_FSELARRA("Opções",{"1 - Opcao 1","2 - Opcao 2","3 - Opcao 3"})

User Function FSELARRA(cTitulo,aOpcoes,l1Elem,lTipoRet)
	/*
	cTitulo = Titulo da Janela
	aOpcoes = Opções que irão aparecer para serem selecionados
	l1Elem  = Definie se a seleção será de apenas de 1 elemento
	lTipoRet= Define o tipo de retorno
	*/
	Local MvParDef:=""	
	Local MvPar	  := ""
	Local i
	
	Private aCat:=aOpcoes

	Default cTitulo :=""
	Default lTipoRet := .T.
	
	l1Elem := If (l1Elem = Nil , .F. , .T.) //Definie se a seleção será de apenas de 1 elemento, .F. mais de um elemento
	
	cAlias := Alias() // Salva Alias Anterior
	
	if Len(aOpcoes)==0
		Help('',1,'FSELARRA',,'As opções não foram inseridas!',1,0)
		Return
	Endif

	IF lTipoRet
		MvPar:=&(Alltrim(ReadVar()))		 // Carrega Nome da Variavel do Get em Questao
		mvRet:=Alltrim(ReadVar())			 // Iguala Nome da Variavel ao Nome variavel de Retorno
	EndIF

	For i := 1 To Len(aCat)
		MvParDef+=Left(aCat[i],1)
	Next
	
	IF f_Opcoes(@MvPar,cTitulo,aCat,MvParDef,12,49,l1Elem)   // Chama funcao f_Opcoes
		&MvRet := mvpar	
	EndIF

	dbSelectArea(cAlias) // Retorna Alias
	
Return( IF( lTipoRet , .T. , MvParDef ) )
Continua página 3 É possível também definir qual campo receberá o retorno, independente do campo que está chamando a janela de opções Para isso, na função, inclua o seu campo Exemplo: U_FMULTIOP('Titulo','YL',,,"EEC_CAMPO")
User Function FMULTIOP(cTitulo,cTabela,l1Elem,lTipoRet,cCampo)

Return( IF( lTipoRet , .T. , MvParDef ) )
Substitua: MvPar:=&(Alltrim(ReadVar())) mvRet:=Alltrim(ReadVar()) Por: __ReadVar := cCampo MvPar :=&(__ReadVar) E substitua: If f_Opcoes(@MvPar,cTitulo,aCat,MvParDef,12,49,l1Elem)       &MvRet := mvpar EndIf Por: If f_Opcoes(@MvPar,cTitulo,aCat,MvParDef,12,49,l1Elem)        &(__ReadVar) := mvpar EndIf Com isso, pode-se usar um gatilho em um campo para chamar a função e ao sair da tela ela preencher um outro campo