Pesquisa de Campos em Telas do Protheus

Pesquisa de Campos em Telas do Protheus

Olá pessoal…

Hoje mostro para vocês um recurso que criei para pesquisa de campos em telas do Protheus.

Um recurso existente no Protheus (e que poucos sabem) é o Ctrl+F, para pesquisa de campos, mas além de não funcionar em todas as telas (inclusive em telas comuns), ele tem alguns bugs de posicionamento.

Pensando nisso, decidi criar uma rotina, que você possa utilizar corretamente uma pesquisa de campos (testei no cadastro de TES, no cadastro de Produto e em um cadastro customizado em MVC). Abaixo um print dela:

Filtragem de campos na tela de TES
Filtragem de campos na tela de TES

Nessa rotina, tem o campo, a aba e o título dele na tela, e ao dar dois cliques ou clicar no confirmar, é posicionado no campo correto. Para funcionar, crie um ponto de entrada no carregamento das telas, no meu caso eu fiz com o AfterLogin (chamado uma única vez no SIGAADV, ou em toda aba aberta no SIGAMDI), e coloquei para ser no atalho Ctrl+L.

Abaixo o código fonte completo:

//Bibliotecas
#Include "Protheus.ch"

//Posições da Grid
#Define POS_ITE    0001 
#Define POS_VAR    0002
#Define POS_ABA    0003
#Define POS_DES    0004

/*/{Protheus.doc} zSearch
Função para pesquisar campos de uma tela de cadastro
@author Atilio
@since 01/12/2017
@version 1.0
@type function
@obs Inicializar ele em um ponto de entrada, por exemplo, no ChkExec ou AfterLogin:

	...
	User Function AfterLogin()
		SetKey(K_CTRL_L, { || u_zSearch() })    //Ctrl + L
	Return
	...
	
	Essa rotina foi testada no cadastro de TES - MATA080
/*/

User Function zSearch()
	Local aArea        := GetArea()
	Local nAtual       := 0
	Local nAbaAux      := 0
	Local cAbaAux      := ""
	//Variáveis de controle
	Private nAtuPvt    := 0
	Private nAbaPvt    := 0
	Private oPai       := GetWndDefault()
	Private aControles := oPai:aControls
	Private cAbaEsc    := ""
	Private cTipoAba   := ""
	//Grid
	Private aDadosOrig := {}
	Private oMsObj
	Private aHeadObj   := {}
	Private aColsObj   := {}
	//Janela
	Private oDlgPesq
	Private nJanLarg   := 500
	Private nJanAltu   := 300
	//Objetos da Janela
	Private oGrpPesq
	Private oSayPesq
	Private oGetPesq
	Private cGetPesq   := Space(100)
	Private oGetAux
	Private cGetAux    := ""
	Private oBtnConf
	Private oBtnCanc
	
	//Percorrendo os objetos criados da tela
	For nAtual := 1 To Len(aControles)
		nAtuPvt := nAtual
		
		//Se tiver variável e descrição
		If Type("aControles[nAtuPvt]:cReadVar") != "U" .And. Type("aControles[nAtuPvt]:cToolTip") != "U"
			//Somente se tiver conteúdo
			If ! Empty(aControles[nAtuPvt]:cReadVar) .And. ! Empty(aControles[nAtuPvt]:cToolTip) .And. 'M->' $ Upper(aControles[nAtuPvt]:cReadVar)
				cAbaAux := GetSx3Cache(StrTran(Upper(aControles[nAtuPvt]:cReadVar), 'M->', ''), "X3_FOLDER")
				
				aAdd(aDadosOrig, {	nAtual,;                                                                               //ID
									aControles[nAtual]:cReadVar,;                                                          //Variável
									cAbaAux,;                                                                              //Aba
									GetSx3Cache(StrTran(Upper(aControles[nAtuPvt]:cReadVar), 'M->', ''), "X3_TITULO"),;    //Descrição
									.F.})                                                                                  //Excluído?
									
				cTipoAba += Iif(" " $ cTipoAba, "", Iif(cAbaAux $ cTipoAba, "", cAbaAux))
			EndIf
		EndIf
	Next
	aColsObj := aClone(aDadosOrig)
	
	//Percorrendo os objetos criados da tela, procurando por abas
	For nAtual := 1 To Len(aControles)
		nAtuPvt := nAtual
		
		//Se tiver aba, guarda a posição dela
		If Type("aControles[nAtuPvt]:aDialogs") == 'A'
			//Somente se o tamanho dela for maior que a variável encontrada
			If Len(aControles[nAtuPvt]:aDialogs) >= Len(cTipoAba)
				nAbaPvt := nAtual
			EndIf
		EndIf
	Next
	
	//Se tiver objetos, monta a tela
	If Len(aDadosOrig) > 0
		//Cabeçalho ... Titulo       Campo      Mask         Tamanho     Dec    Valid   Usado  Tip  F3  CBOX
		aAdd(aHeadObj, {"Item",      "XX_ITEM", "@E 9999",   0004,       0000,  ".F.",  ".F.", "N", "", ""})
		aAdd(aHeadObj, {"Variável",  "XX_VAR",  "",          0020,       0000,  ".F.",  ".F.", "C", "", ""})
		aAdd(aHeadObj, {"Nº Aba",    "XX_ABA",  "",          0001,       0000,  ".F.",  ".F.", "C", "", ""})
		aAdd(aHeadObj, {"Título",    "XX_DESC", "",          0020,       0000,  ".F.",  ".F.", "C", "", ""})
		
		//Criando a janela
		DEFINE MSDIALOG oDlgPesq TITLE "Pesquisar" FROM 000, 000  TO nJanAltu, nJanLarg COLORS 0, 16777215 PIXEL
		
			//Título do Grupo
			@ 003, 003 GROUP oGrpPesq TO (nJanAltu/2)-1, (nJanLarg/2)-1 PROMPT "zSearch - Pesquisa de Campos: " OF oDlgPesq COLOR 0, 16777215 PIXEL
			
				//Campo para pesquisar
				@ 016, 006   SAY   oSayPesq PROMPT "Pesquisar: " SIZE 030,             012 OF oDlgPesq PIXEL
				@ 013, 036   MSGET oGetPesq VAR	   cGetPesq	     SIZE (nJanLarg/2)-42, 012 OF oDlgPesq COLORS 0, 16777215 VALID (fVldPesq()) PIXEL
			
				//Dados dos Objetos encontrados
				oMsObj := MsNewGetDados():New(	030,;                    //nTop
												006,;                    //nLeft
												(nJanAltu/2)-23,;        //nBottom
												(nJanLarg/2)-4,;         //nRight
												0,;                      //nStyle
												"",;                     //cLinhaOk
												,;                       //cTudoOk
												"",;                     //cIniCpos
												{},;                     //aAlter
												,;                       //nFreeze
												99999,;                  //nMax
												,;                       //cFieldOK
												,;                       //cSuperDel
												,;                       //cDelOk
												oDlgPesq,;               //oWnd
												aHeadObj,;               //aHeader
												aColsObj)                //aCols
				oMsObj:lActive := .F.
				oMsObj:bChange := {|| fAtuAux()}
				oMsObj:oBrowse:blDblClick := {|| fConfirma() }
				
				//Criando get invisível que terá dados do registro posicionado
				@ (nJanAltu / 2) - 022, 005 MSGET oGetAux VAR cGetAux      SIZE 200, 18  NO BORDER  OF oDlgPesq PIXEL
				oGetAux:setCSS("QLineEdit{color:#FF0000; background-color:#FEFEFE;}")
				oGetAux:lActive := .F.
				
				//Botões
				@ (nJanAltu/2)-18, (nJanLarg/2)-((0042*1)+6) BUTTON oBtnConf PROMPT "Confirmar" SIZE 040, 013 OF oDlgPesq ACTION(fConfirma())     PIXEL
				@ (nJanAltu/2)-18, (nJanLarg/2)-((0042*2)+6) BUTTON oBtnCanc PROMPT "Cancelar"  SIZE 040, 013 OF oDlgPesq ACTION(oDlgPesq:End())  PIXEL
				
				//Colocando o foco na pesquisa
				oGetPesq:SetFocus()
		ACTIVATE MSDIALOG oDlgPesq CENTERED
	EndIf
	
	//Posiciona no campo
	If nAtuPvt != 0
		//Se tiver abas
		If nAbaPvt != 0
			nAbaAux := 0
			
			//Se a aba estiver em branco, será a última aba
			If Empty(cAbaEsc)
				nAbaAux := Len(aControles[nAbaPvt]:aDialogs)
				
			//Se for numérico, posicionará corretamente
			ElseIf cAbaEsc $ ("0,1,2,3,4,5,6,7,8,9")
				nAbaAux := Val(cAbaEsc)
			
			//Se for letra, converte para número e posiciona corretamente
			Else
				nAbaAux := (Asc(Upper(cAbaEsc)) - 64) + 9
			EndIf
			
			//Tratativa para não colocar em aba que não deve
			If nAbaAux > Len(aControles[nAbaPvt]:aDialogs)
				nAbaAux := Len(aControles[nAbaPvt]:aDialogs)
			EndIf
			
			aControles[nAbaPvt]:SetOption(nAbaAux)
			aControles[nAbaPvt]:Refresh()
		EndIf
		
		//Coloca o foco no campo
		aControles[nAtuPvt]:SetFocus()
	EndIf
	
	RestArea(aArea)
Return

/*---------------------------------------------------------------------*
 | Func:  fVldPesq                                                     |
 | Desc:  Função que filtra a pesquisa na grid                         |
 *---------------------------------------------------------------------*/

Static Function fVldPesq()
	Local lRet      := .T.
	Local aDadosAux := {}
	Local nAtual    := 0
	Local cFiltro   := Alltrim(FWNoAccent(Upper(cGetPesq)))
	
	//Caso não tenha filtro
	If Empty(cFiltro)
		aDadosAux := aClone(aDadosOrig)
	Else
		//Percorre os dados originais
		For nAtual := 1 To Len(aDadosOrig)
			If cFiltro $ FWNoAccent(Upper(aDadosOrig[nAtual][POS_VAR])) .Or. cFiltro $ FWNoAccent(Upper(aDadosOrig[nAtual][POS_DES]))
				aAdd(aDadosAux, aClone(aDadosOrig[nAtual]))
			EndIf
		Next
	EndIf
	
	//Se não tiver dados
	If Len(aDadosAux) == 0
		aAdd(aDadosAux, {	0,;        //ID
							"",;       //Variável
							"",;       //Aba
							"",;       //Descrição
							.F.}) 
	EndIf
	
	//Seta o novo array filtrado
	oMsObj:SetArray(aDadosAux)
	oMsObj:Refresh()
	fAtuAux()
Return lRet

/*---------------------------------------------------------------------*
 | Func:  fConfirma                                                    |
 | Desc:  Função que confirma para posicionar no campo pesquisado      |
 *---------------------------------------------------------------------*/

Static Function fConfirma()
	Local aColsAux := oMsObj:aCols
	Local nLinAtu  := oMsObj:nAt
	
	//Pegando o item atual
	nAtuPvt := 0
	nAtuPvt := aColsAux[nLinAtu][POS_ITE]
	cAbaEsc := ""
	cAbaEsc := aColsAux[nLinAtu][POS_ABA]
	
	//Fecha a tela
	oDlgPesq:End()
Return

/*---------------------------------------------------------------------*
 | Func:  fAtuAux                                                      |
 | Desc:  Função que atualiza a descrição                              |
 *---------------------------------------------------------------------*/

Static Function fAtuAux()
	Local aColsAux := oMsObj:aCols
	Local nLinAtu  := oMsObj:nAt
	
	//Atualiza o texto auxiliar
	cGetAux := Alltrim(aColsAux[nLinAtu][POS_DES])
	oGetAux:Refresh()
Return

Esses e outros códigos, estão disponíveis gratuitamente no nosso GitHub, acesse em github.com/dan-atilio/AdvPL.
Caso queira uma customização específica para sua empresa, saiba mais em nossa Loja.

Bom pessoal, por hoje é só.
Abraços e até a próxima.

About Dan_Atilio

Analista e desenvolvedor de sistemas. Técnico em Informática pelo CTI da Unesp. Graduado em Banco de Dados pela Fatec Bauru. Entusiasta de soluções Open Source e blogueiro nas horas vagas. Autor do projeto Terminal de Informação, onde são postados tutoriais e notícias envolvendo o mundo da tecnologia.

5 comentários em “Pesquisa de Campos em Telas do Protheus

  1. Bom dia!
    Coloquei para teste, ele entra na função zSearch coloquei um alerta lá… Porém ele não abre a tela para pesquisa. Testei tanto no cadastro de TES como no cadastro de produto.
    O que poderia ser?

    1. Boa noite Welder, tudo bem?
      Eu vi um caso desse em que estava ativado o parâmetro MV_ENCHOLD, tente alterar ele, para deixar da forma nova (mais de duas colunas na tela).
      Um grande abraço.

  2. Boa tarde!
    Obrigado pelo retorno, realmente é a questão do parâmetro. Porém utilizamos o MV_ENCHOLD = 1. Saberia dizer se existe alguma forma de utilizar a função sem que precise alterar o parâmetro? Ou só alterando a rotina da pesquisa?
    Desde já obrigado.

    1. Boa noite Welder, tudo bem?
      Então, acho que para o caso de utilizar o MV_ENCHOLD, teria que analisar o código fonte e reconstruir ele para esse tipo de tela.
      Talvez o mais fácil é alterar o parâmetro mesmo.
      Um grande abraço.

Deixe uma resposta

%d blogueiros gostam disto: