No artigo de hoje, vou mostrar como identificar em qual coluna foi clicado em uma grid usando FWBrowse.
Recentemente, estávamos conversando no Discord, e meu amigo Alison Kaique ( LinkedIn ) comentou que um método interessante no FWBrowse é o ColPos que retorna a coluna que foi clicado.
Pensando nisso, decidi montar um exemplo, ao dar duplo clique na grid, para exibir a informação (no caso você pode até adaptar o exemplo para mostrar um ParamBox ou algum outro recurso para atualizar a informação da grid).
Abaixo um print de exemplo:
E abaixo o código fonte desenvolvido:
#Include "Totvs.ch"
/*/{Protheus.doc} User Function zGrid
Visualizacao de Grupos de Produtos com FWBrowse e FWTemporaryTable com duplo clique
@type Function
@author Atilio
@since 09/06/2021
@version version
/*/
User Function zGrid()
Local aArea := GetArea()
//Fontes
Local cFontUti := "Tahoma"
Local oFontAno := TFont():New(cFontUti,,-38)
Local oFontSub := TFont():New(cFontUti,,-20)
Local oFontSubN := TFont():New(cFontUti,,-20,,.T.)
Local oFontBtn := TFont():New(cFontUti,,-14)
//Janela e componentes
Private oDlgGrp
Private oPanGrid
Private oGetGrid
Private aColunas := {}
Private cAliasTab := "TMPSBM"
//Tamanho da janela
Private aTamanho := MsAdvSize()
Private nJanLarg := aTamanho[5]
Private nJanAltu := aTamanho[6]
//Cria a temporária
oTempTable := FWTemporaryTable():New(cAliasTab)
//Adiciona no array das colunas as que serão incluidas (Nome do Campo, Tipo do Campo, Tamanho, Decimais)
aFields := {}
aAdd(aFields, {"XXCODIGO", "C", TamSX3('BM_GRUPO')[01], 0})
aAdd(aFields, {"XXDESCRI", "C", TamSX3('BM_DESC')[01], 0})
aAdd(aFields, {"XXSTATUS", "C", TamSX3('BM_STATUS')[01], 0})
aAdd(aFields, {"XXPROORI", "C", TamSX3('BM_PROORI')[01], 0})
aAdd(aFields, {"XXTOTALP", "N", 18, 0})
aAdd(aFields, {"XXSBMREC", "N", 18, 0})
//Define as colunas usadas, adiciona indice e cria a temporaria no banco
oTempTable:SetFields( aFields )
oTempTable:AddIndex("1", {"XXCODIGO"} )
oTempTable:Create()
//Monta o cabecalho
fMontaHead()
//Montando os dados, eles devem ser montados antes de ser criado o FWBrowse
FWMsgRun(, {|oSay| fMontDados(oSay) }, "Processando", "Buscando grupos")
//Criando a janela
DEFINE MSDIALOG oDlgGrp TITLE "Grupos de Produtos" FROM 000, 000 TO nJanAltu, nJanLarg COLORS 0, 16777215 PIXEL
//Labels gerais
@ 004, 003 SAY "FAT" SIZE 200, 030 FONT oFontAno OF oDlgGrp COLORS RGB(149,179,215) PIXEL
@ 004, 050 SAY "Listagem de" SIZE 200, 030 FONT oFontSub OF oDlgGrp COLORS RGB(031,073,125) PIXEL
@ 014, 050 SAY "Grupos de Produtos" SIZE 200, 030 FONT oFontSubN OF oDlgGrp COLORS RGB(031,073,125) PIXEL
//Botões
@ 006, (nJanLarg/2-001)-(0052*01) BUTTON oBtnFech PROMPT "Fechar" SIZE 050, 018 OF oDlgGrp ACTION (oDlgGrp:End()) FONT oFontBtn PIXEL
//Dados
@ 024, 003 GROUP oGrpDad TO (nJanAltu/2-003), (nJanLarg/2-003) PROMPT "Grupos (Para ver a legenda basta clicar duas vezes em alguma bolinha): " OF oDlgGrp COLOR 0, 16777215 PIXEL
oGrpDad:oFont := oFontBtn
oPanGrid := tPanel():New(033, 006, "", oDlgGrp, , , , RGB(000,000,000), RGB(254,254,254), (nJanLarg/2 - 13), (nJanAltu/2 - 45))
oGetGrid := FWBrowse():New()
oGetGrid:DisableFilter()
oGetGrid:DisableConfig()
oGetGrid:DisableReport()
oGetGrid:DisableSeek()
oGetGrid:DisableSaveConfig()
oGetGrid:SetFontBrowse(oFontBtn)
oGetGrid:SetAlias(cAliasTab)
oGetGrid:SetDataTable()
oGetGrid:SetInsert(.F.)
oGetGrid:SetDelete(.F., { || .F. })
oGetGrid:lHeaderClick := .F.
oGetGrid:AddLegend(cAliasTab + "->XXPROORI == '0'", "RED", "Nao Original")
oGetGrid:AddLegend(cAliasTab + "->XXPROORI == '1'", "GREEN", "Original")
oGetGrid:AddLegend("Empty(" + cAliasTab + "->XXPROORI)", "BLACK", "Sem Classificacao")
oGetGrid:SetColumns(aColunas)
oGetGrid:SetOwner(oPanGrid)
oGetGrid:SetDoubleClick( {|| fGrupo() } )
oGetGrid:Activate()
ACTIVATE MsDialog oDlgGrp CENTERED
//Deleta a temporaria
oTempTable:Delete()
RestArea(aArea)
Return
Static Function fMontaHead()
Local nAtual
Local aHeadAux := {}
//Adicionando colunas
//[1] - Campo da Temporaria
//[2] - Titulo
//[3] - Tipo
//[4] - Tamanho
//[5] - Decimais
//[6] - Máscara
aAdd(aHeadAux, {"XXCODIGO", "Código", "C", TamSX3('BM_GRUPO')[01], 0, ""})
aAdd(aHeadAux, {"XXDESCRI", "Descricao", "C", TamSX3('BM_DESC')[01], 0, ""})
aAdd(aHeadAux, {"XXSTATUS", "Status Grupo", "C", TamSX3('BM_STATUS')[01], 0, ""})
aAdd(aHeadAux, {"XXPROORI", "Procedencia", "C", TamSX3('BM_PROORI')[01], 0, ""})
aAdd(aHeadAux, {"XXTOTALP", "Total de Produtos", "N", 18, 0, "@E 999,999,999,999,999,999"})
aAdd(aHeadAux, {"XXSBMREC", "SBM RecNo", "N", 18, 0, "@E 999,999,999,999,999,999"})
//Percorrendo e criando as colunas
For nAtual := 1 To Len(aHeadAux)
oColumn := FWBrwColumn():New()
oColumn:SetData(&("{|| " + cAliasTab + "->" + aHeadAux[nAtual][1] +"}"))
oColumn:SetTitle(aHeadAux[nAtual][2])
oColumn:SetType(aHeadAux[nAtual][3])
oColumn:SetSize(aHeadAux[nAtual][4])
oColumn:SetDecimal(aHeadAux[nAtual][5])
oColumn:SetPicture(aHeadAux[nAtual][6])
aAdd(aColunas, oColumn)
Next
Return
Static Function fMontDados(oSay)
Local aArea := GetArea()
Local cQry := ""
Local nAtual := 0
Local nTotal := 0
//Zera a grid
aColsGrid := {}
//Montando a query
oSay:SetText("Montando a consulta")
cQry := " SELECT " + CRLF
cQry += " BM_GRUPO, " + CRLF
cQry += " BM_DESC, " + CRLF
cQry += " BM_STATUS, " + CRLF
cQry += " BM_PROORI, " + CRLF
cQry += " ( " + CRLF
cQry += " SELECT " + CRLF
cQry += " COUNT(*) " + CRLF
cQry += " FROM " + CRLF
cQry += " " + RetSQLName('SB1') + " SB1 " + CRLF
cQry += " WHERE " + CRLF
cQry += " B1_FILIAL = '" + FWxFilial('SB1') + "' " + CRLF
cQry += " AND B1_GRUPO = BM_GRUPO " + CRLF
cQry += " AND B1_MSBLQL != '1' " + CRLF
cQry += " AND SB1.D_E_L_E_T_ = ' ' " + CRLF
cQry += " ) AS TOT_PROD, " + CRLF
cQry += " SBM.R_E_C_N_O_ AS SBMREC " + CRLF
cQry += " FROM " + CRLF
cQry += " " + RetSQLName('SBM') + " SBM " + CRLF
cQry += " WHERE " + CRLF
cQry += " BM_FILIAL = '" + FWxFilial('SBM') + "' " + CRLF
cQry += " AND SBM.D_E_L_E_T_ = ' ' " + CRLF
cQry += " ORDER BY " + CRLF
cQry += " BM_GRUPO " + CRLF
//Executando a query
oSay:SetText("Executando a consulta")
PLSQuery(cQry, "QRY_SBM")
//Se houve dados
If ! QRY_SBM->(EoF())
//Pegando o total de registros
DbSelectArea("QRY_SBM")
Count To nTotal
QRY_SBM->(DbGoTop())
//Enquanto houver dados
While ! QRY_SBM->(EoF())
//Muda a mensagem na regua
nAtual++
oSay:SetText("Adicionando registro " + cValToChar(nAtual) + " de " + cValToChar(nTotal) + "...")
RecLock(cAliasTab, .T.)
(cAliasTab)->XXCODIGO := QRY_SBM->BM_GRUPO
(cAliasTab)->XXDESCRI := QRY_SBM->BM_DESC
(cAliasTab)->XXSTATUS := QRY_SBM->BM_STATUS
(cAliasTab)->XXPROORI := QRY_SBM->BM_PROORI
(cAliasTab)->XXTOTALP := QRY_SBM->TOT_PROD
(cAliasTab)->XXSBMREC := QRY_SBM->SBMREC
(cAliasTab)->(MsUnlock())
QRY_SBM->(DbSkip())
EndDo
Else
MsgStop("Nao foi encontrado registros!", "Atencao")
RecLock(cAliasTab, .T.)
(cAliasTab)->XXCODIGO := ""
(cAliasTab)->XXDESCRI := ""
(cAliasTab)->XXSTATUS := ""
(cAliasTab)->XXPROORI := ""
(cAliasTab)->XXTOTALP := 0
(cAliasTab)->XXSBMREC := 0
(cAliasTab)->(MsUnlock())
EndIf
QRY_SBM->(DbCloseArea())
(cAliasTab)->(DbGoTop())
RestArea(aArea)
Return
Static Function fGrupo()
Local lLegenda := .T. //.T. se tiver bolinha de legenda e .F. se não tiver, para poder subtrair da linha abaixo
Local nColuna := oGetGrid:ColPos() - Iif(lLegenda, 1, 0)
Local cTitulo
Local xConteu
//Se for uma coluna válida (não for legenda)
If nColuna != 0
cTitulo := Alltrim(aColunas[nColuna]:cTitle)
xConteu := eVal(aColunas[nColuna]:bData)
//Tratativa se for numérico ou caractere para exibir como caractere
If aColunas[nColuna]:cType == "N"
xConteu := cValToChar(xConteu)
ElseIf aColunas[nColuna]:cType == "D"
xConteu := dToC(xConteu)
EndIf
MsgInfo("Estou no grupo: " + (cAliasTab)->XXCODIGO + CRLF + "Coluna: " + cTitulo + CRLF + "Conteudo: " + xConteu, "Atencao")
EndIf
Return
Caso você use array, e seja necessário atualizar o conteúdo, poderia fazer algo nesse sentido:
//Pegando a linha e a coluna nLinha := oGetGrid:At() nColuna := oGetGrid:ColPos() //Editando a variavel de aCols da grid na linha e coluna aColsGrid[nLinha][nColuna] := "TST" //Posicionando na linha que foi editada e forçando a atualização da tela oGetGrid:GoTo(nLinha, .T.)
Bom pessoal, por hoje é só.
Abraços e até a próxima.

Parabéns por mais um post meu amigo, como sempre qualidade no ensino e didática imprescindível.
Abraço e Deus abençoe.
Amém Alison.
Obrigado pelo comentário jovem.
Grande abraço.
Showww !!! Esse é o Atilio, nunca coloca na gaveta os conhecimentos, parabéns e sucesso
Opa, obrigado pelo feedback Douglas, bondade sua jovem.
Grande abraço.