Migrando do MSNewGetDados para FWBrowse e MVC

Hoje vou mostrar como migrar para outros tipos de grid já que a MsNewGetDados foi descontinuada.

Uma das dúvidas que mais me perguntam, é como fazer grids em telas customizadas no Protheus, já que a MsNewGetDados, a clássica grid, foi descontinuada.

Ah Daniel, mas e se eu continuar usando MsNewGetDados tem algum problema? Pois bem jovens, faz um bom tempo que a classe foi descontinuada pela TOTVS, provavelmente problema não terá, pois eles irão manter o legado, mas se algum dia acontecer algum bug na Lib, ou se forem atualizar alguma coisa do Core do Protheus e a MsNewGetDados apresente algum comportamento estranho, você não poderá abrir nenhum chamado e dificilmente conseguirá resolver, a não ser se migrar a rotina para uma classe mais nova.

Pois bem, pensando nisso, venho trazer para vocês 3 exemplos de como fazer grids sem a MsNewGetDados e a vantagem e desvantagem de cada uma delas.

Dois exemplos, eu utilizo o FWBrowse, que é facilmente colocado em qualquer dialog ou panel, porém ele não permite alteração, então esse seria um exemplo apenas para visualização de dados.

Já o terceiro exemplo, eu uso uma grid em MVC, nessa sendo possível a manipulação, conforme o link do TDN – https://centraldeatendimento.totvs.com/hc/pt-br/articles/360047143634-MP-ADVPL-Criando-uma-tela-MVC-s%C3%B3-com-GRID . Nesse exemplo, criei uma temporária, e chamei a tela em seguida, porém você pode usar tabelas padrões e até interceptar o commit com FWModelEvent ( https://tdn.totvs.com/pages/viewpage.action?pageId=269552294 ).

FWBrowse com FWTemporaryTable (Grid em Dialog com Tabela Temporária):

FWBrowse com FWTemporaryTable

#Include "Totvs.ch"

/*/{Protheus.doc} User Function zGrid
Visualizacao de Grupos de Produtos com FWBrowse e FWTemporaryTable
@type  Function
@author Atilio
@since  14/06/2020
@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
        @ 006, (nJanLarg/2-001)-(0052*02) BUTTON oBtnLege  PROMPT "Ver Grupo"     SIZE 050, 018 OF oDlgGrp ACTION (fGrupo()) 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: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()
    MsgInfo("Estou no grupo: " + (cAliasTab)->XXCODIGO, "Atencao")
Return

FWBrowse com Array (Grid em Dialog com Array Multidimensional):

FWBrowse com Array

#Include "Totvs.ch"

/*/{Protheus.doc} User Function zGrid
Visualizacao de Grupos de Produtos com FWBrowse e Array
@type  Function
@author Atilio
@since  14/06/2020
@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 aHeaderGrid := {}
    Private aColsGrid := {}
    //Tamanho da janela
    Private	aTamanho := MsAdvSize()
	Private	nJanLarg := aTamanho[5]
	Private	nJanAltu := aTamanho[6]

    //Monta o cabecalho
    fMontaHead()

	//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
        @ 006, (nJanLarg/2-001)-(0052*02) BUTTON oBtnLege  PROMPT "Ver Grupo"     SIZE 050, 018 OF oDlgGrp ACTION (fGrupo()) 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:SetDataArray()
            oGetGrid:lHeaderClick :=.f.
            oGetGrid:AddLegend("oGetGrid:oData:aArray[oGetGrid:At(), 4] == '0'", "RED",    "Nao Original")
            oGetGrid:AddLegend("oGetGrid:oData:aArray[oGetGrid:At(), 4] == '1'", "GREEN",  "Original")
            oGetGrid:AddLegend("Empty(oGetGrid:oData:aArray[oGetGrid:At(), 4])", "BLACK",  "Sem Classificacao")
            oGetGrid:SetColumns(aHeaderGrid)
            oGetGrid:SetArray(aColsGrid)
            oGetGrid:SetOwner(oPanGrid)
            oGetGrid:Activate()

        FWMsgRun(, {|oSay| fMontDados(oSay) }, "Processando", "Buscando grupos")
	ACTIVATE MsDialog oDlgGrp CENTERED

    RestArea(aArea)
Return

Static Function fMontaHead()
    Local nAtual
    Local aHeadAux := {}

    //Adicionando colunas
    //[1] - Titulo
    //[2] - Tipo
    //[3] - Tamanho
    //[4] - Decimais
    //[5] - Máscara
    aAdd(aHeadAux, {"Código",            "C", TamSX3('BM_GRUPO')[01],   0, ""})
    aAdd(aHeadAux, {"Descricao",         "C", TamSX3('BM_DESC')[01],    0, ""})
    aAdd(aHeadAux, {"Status Grupo",      "C", TamSX3('BM_STATUS')[01],  0, ""})
    aAdd(aHeadAux, {"Procedencia",       "C", TamSX3('BM_PROORI')[01],  0, ""})
    aAdd(aHeadAux, {"Total de Produtos", "N", 18,                       0, "@E 999,999,999,999,999,999"})
    aAdd(aHeadAux, {"SBM RecNo",         "N", 18,                       0, "@E 999,999,999,999,999,999"})

    //Percorrendo e criando as colunas
    For nAtual := 1 To Len(aHeadAux)
		aAdd(aHeaderGrid, FWBrwColumn():New())
		aHeaderGrid[nAtual]:SetData(&("{||oGetGrid:oData:aArray[oGetGrid:At(),"+Str(nAtual)+"]}"))
		aHeaderGrid[nAtual]:SetTitle( aHeadAux[nAtual][1] )
        aHeaderGrid[nAtual]:SetType(aHeadAux[nAtual][2] )
		aHeaderGrid[nAtual]:SetSize( aHeadAux[nAtual][3] )
		aHeaderGrid[nAtual]:SetDecimal( aHeadAux[nAtual][4] )
		aHeaderGrid[nAtual]:SetPicture( aHeadAux[nAtual][5] )
	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) + "...")

            aAdd(aColsGrid, {;
                QRY_SBM->BM_GRUPO,;
                QRY_SBM->BM_DESC,;
                QRY_SBM->BM_STATUS,;
                QRY_SBM->BM_PROORI,;
                QRY_SBM->TOT_PROD,;
                QRY_SBM->SBMREC,;
                .F.;
            })

            QRY_SBM->(DbSkip())
        EndDo

    Else
        MsgStop("Nao foi encontrado registros!", "Atencao")

        aAdd(aColsGrid, {;
            "",;
            "",;
            "",;
            "",;
            0,;
            0,;
            .F.;
        })
    EndIf
    QRY_SBM->(DbCloseArea())

    //Define o array
    oSay:SetText("Atribuindo os dados na tela")
    oGetGrid:SetArray(aColsGrid)
    oGetGrid:Refresh()

    RestArea(aArea)
Return

Static Function fGrupo()
    Local nLinha   := oGetGrid:At()   
    Local nColCod  := 1

    MsgInfo("Estou no grupo: " + aColsGrid[nLinha][nColCod], "Atencao")
Return

Grid em MVC (Grid alterável utilizando conceito de MVC em AdvPL):

Grid em MVC

#Include 'Totvs.ch'
#Include 'FWMVCDef.ch'

Static cTitle := "Grupo de Produtos em MVC"
Static cKey    := "FAKE"
Static nTamFake := 15

/*/{Protheus.doc} User Function zGrid
Visualizacao de Grupos de Produtos em MVC (com tabela temporaria)
@type  Function
@author Atilio
@since  14/06/2020
@version version
@obs Foi baseado no exemplo de Izac Ciszevski (https://centraldeatendimento.totvs.com/hc/pt-br/articles/360047143634-MP-ADVPL-Criando-uma-tela-MVC-s%C3%B3-com-GRID)
/*/

User Function zGrid()
	Local aArea := GetArea()
    Private cAliasTmp := "TMPSBM"

    //Cria a temporária
    oTempTable := FWTemporaryTable():New(cAliasTmp)
    
    //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})
    
    //Define as colunas usadas, adiciona indice e cria a temporaria no banco
    oTempTable:SetFields( aFields )
    oTempTable:AddIndex("1", {"XXCODIGO"} )
    oTempTable:Create()

    //Executa a inclusao na tela
    FWExecView('GRID Sem Cabeçalho', "VIEWDEF.zGrid", MODEL_OPERATION_INSERT, , { || .T. }, , 30)

    //Agora percorre todos os dados digitados
    (cAliasTmp)->(DbGoTop())
    While ! (cAliasTmp)->(EoF())
        MsgInfo("Código: " + (cAliasTmp)->XXCODIGO + ", Descrição: " + (cAliasTmp)->XXDESCRI, "Atenção")
        (cAliasTmp)->(DbSkip())
    EndDo

    //Deleta a temporaria
    oTempTable:Delete()
	
	RestArea(aArea)
Return

Static Function ModelDef()
    Local oModel  As Object
    Local oStrField As Object
    Local oStrGrid As Object

    //Criamos aqui uma estrutura falsa que sera uma tabela que ficara escondida no cabecalho
    oStrField := FWFormModelStruct():New()
    oStrField:AddTable('' , { 'XXTABKEY' } , cTitle, {|| ''})
    oStrField:AddField('String 01' , 'Campo de texto' , 'XXTABKEY' , 'C' , nTamFake)

    //Criamos aqui a estrutura da grid
    oStrGrid := FWFormModelStruct():New() 
    oStrGrid:AddTable(cAliasTmp, {'XXTABKEY', 'XXCODIGO', 'XXDESCRI'}, "Temporaria")
     
    //Adiciona os campos da estrutura
    oStrGrid:AddField(;
        "Codigo",;                                                                                  // [01]  C   Titulo do campo
        "Codigo",;                                                                                  // [02]  C   ToolTip do campo
        "XXCODIGO",;                                                                                // [03]  C   Id do Field
        "C",;                                                                                       // [04]  C   Tipo do campo
        06,;                                                                                        // [05]  N   Tamanho do campo
        0,;                                                                                         // [06]  N   Decimal do campo
        Nil,;                                                                                       // [07]  B   Code-block de validação do campo
        Nil,;                                                                                       // [08]  B   Code-block de validação When do campo
        {},;                                                                                        // [09]  A   Lista de valores permitido do campo
        .T.,;                                                                                       // [10]  L   Indica se o campo tem preenchimento obrigatório
        FwBuildFeature( STRUCT_FEATURE_INIPAD, cAliasTmp+"->XXCODIGO" ),;                           // [11]  B   Code-block de inicializacao do campo
        .T.,;                                                                                       // [12]  L   Indica se trata-se de um campo chave
        .F.,;                                                                                       // [13]  L   Indica se o campo pode receber valor em uma operação de update.
        .F.)                                                                                        // [14]  L   Indica se o campo é virtual
    oStrGrid:AddField(;
        "Descricao",;                                                                               // [01]  C   Titulo do campo
        "Descricao",;                                                                               // [02]  C   ToolTip do campo
        "XXDESCRI",;                                                                                // [03]  C   Id do Field
        "C",;                                                                                       // [04]  C   Tipo do campo
        50,;                                                                                        // [05]  N   Tamanho do campo
        0,;                                                                                         // [06]  N   Decimal do campo
        Nil,;                                                                                       // [07]  B   Code-block de validação do campo
        Nil,;                                                                                       // [08]  B   Code-block de validação When do campo
        {},;                                                                                        // [09]  A   Lista de valores permitido do campo
        .T.,;                                                                                       // [10]  L   Indica se o campo tem preenchimento obrigatório
        FwBuildFeature( STRUCT_FEATURE_INIPAD, cAliasTmp+"->XXDESCRI" ),;                           // [11]  B   Code-block de inicializacao do campo
        .F.,;                                                                                       // [12]  L   Indica se trata-se de um campo chave
        .F.,;                                                                                       // [13]  L   Indica se o campo pode receber valor em uma operação de update.
        .F.)                                                                                        // [14]  L   Indica se o campo é virtual

    //Agora criamos o modelo de dados da nossa tela
    oModel := MPFormModel():New('zGridM')
    oModel:AddFields('CABID', , oStrField)
    oModel:AddGrid('GRIDID', 'CABID', oStrGrid)
    oModel:SetRelation('GRIDID', { { 'XXTABKEY', 'XXTABKEY' } })
    oModel:SetDescription(cTitle)
    oModel:SetPrimaryKey({ 'XXTABKEY' })

    //Ao ativar o modelo, irá alterar o campo do cabeçalho mandando o conteúdo FAKE pois é necessário alteração no cabeçalho
    oModel:SetActivate({ | oModel | FwFldPut("XXTABKEY", cKey) })
Return oModel

Static Function ViewDef()
    Local oView    As Object
    Local oModel   As Object
    Local oStrCab  As Object
    Local oStrGrid As Object

    //Criamos agora a estrtutura falsa do cabeçalho na visualização dos dados
    oStrCab := FWFormViewStruct():New()
    oStrCab:AddField('XXTABKEY' , '01' , 'String 01' , 'Campo de texto', , 'C')

    //Agora a estrutura da Grid
    oStrGrid := FWFormViewStruct():New()
 
    //Adicionando campos da estrutura
    oStrGrid:AddField(;
        "XXCODIGO",;                // [01]  C   Nome do Campo
        "01",;                      // [02]  C   Ordem
        "Codigo",;                  // [03]  C   Titulo do campo
        "Codigo",;                  // [04]  C   Descricao do campo
        Nil,;                       // [05]  A   Array com Help
        "C",;                       // [06]  C   Tipo do campo
        "@!",;                      // [07]  C   Picture
        Nil,;                       // [08]  B   Bloco de PictTre Var
        Nil,;                       // [09]  C   Consulta F3
        .T.,;                       // [10]  L   Indica se o campo é alteravel
        Nil,;                       // [11]  C   Pasta do campo
        Nil,;                       // [12]  C   Agrupamento do campo
        Nil,;                       // [13]  A   Lista de valores permitido do campo (Combo)
        Nil,;                       // [14]  N   Tamanho maximo da maior opção do combo
        Nil,;                       // [15]  C   Inicializador de Browse
        Nil,;                       // [16]  L   Indica se o campo é virtual
        Nil,;                       // [17]  C   Picture Variavel
        Nil)                        // [18]  L   Indica pulo de linha após o campo
    oStrGrid:AddField(;
        "XXDESCRI",;                // [01]  C   Nome do Campo
        "02",;                      // [02]  C   Ordem
        "Descricao",;               // [03]  C   Titulo do campo
        "Descricao",;               // [04]  C   Descricao do campo
        Nil,;                       // [05]  A   Array com Help
        "C",;                       // [06]  C   Tipo do campo
        "@!",;                      // [07]  C   Picture
        Nil,;                       // [08]  B   Bloco de PictTre Var
        Nil,;                       // [09]  C   Consulta F3
        .T.,;                       // [10]  L   Indica se o campo é alteravel
        Nil,;                       // [11]  C   Pasta do campo
        Nil,;                       // [12]  C   Agrupamento do campo
        Nil,;                       // [13]  A   Lista de valores permitido do campo (Combo)
        Nil,;                       // [14]  N   Tamanho maximo da maior opção do combo
        Nil,;                       // [15]  C   Inicializador de Browse
        Nil,;                       // [16]  L   Indica se o campo é virtual
        Nil,;                       // [17]  C   Picture Variavel
        Nil)                        // [18]  L   Indica pulo de linha após o campo

    //Carrega o ModelDef
    oModel  := FWLoadModel('zGrid')

    //Agora na visualização, carrega o modelo, define o cabeçalho e a grid, e no cabeçalho coloca 0% de visualização, e na grid coloca 100%
    oView := FwFormView():New()
    oView:SetModel(oModel)
    oView:AddField('CAB', oStrCab, 'CABID')
    oView:AddGrid('GRID', oStrGrid, 'GRIDID')
    oView:CreateHorizontalBox('TOHID', 0)
    oView:CreateHorizontalBox('TOSHOW', 100)
    oView:SetOwnerView('CAB' , 'TOHID')
    oView:SetOwnerView('GRID', 'TOSHOW')
    oView:SetDescription(cTitle)
Return oView

Bom pessoal, por hoje é só.

Abraços e até a próxima.

Dan Atilio (Daniel Atilio)
Especialista em Engenharia de Software pela FIB. Entusiasta de soluções Open Source. E blogueiro nas horas vagas.

14 Responses

  1. Armando Neto disse:

    Muito bom.
    Estou trabalhando em algumas personalizações, que vão trabalhar exatamente com este conceito MVC.
    Obrigado por compartilhar.

  2. Renato Ikeda disse:

    Obrigado pelo material técnico de excelente qualidade eu estava procurando como usar temporárias com grid em MVC e caí aqui no seu site.
    Agora estou com a seguinte dificuldade na classe MsNewGetDados tínhamos a opção de congelar a primeira coluna para facilitar a visualização / navegação, vc sabe se isto é possível no FwFormGrid?

    Grato!

  3. Flavio Dias disse:

    Bom dia, como eu faria para dar um refresc nela 1 opção após carregado a grid?

    • Dan_Atilio disse:

      Boa tarde.
      Se você usar com uma FWTemporaryTable, você teria que dar um reclock na temporária, depois forçar uma atualização indo ao fim e voltando ao topo, +- assim:
      (cAliasTmp)->(DbGoTop())
      oGetGrid:GoBottom(.T.)
      oGetGrid:Refresh(.T.)
      oGetGrid:GoTop(.T.)
      oGetGrid:Refresh(.T.)

  4. Eduardo Antunes disse:

    Bom dia.
    Estou tentando implementar uma rotina que a presenta detalhes ao clicar em uma linha do controle FWBrowse(). Você saberia dizer qual o método?

    • Dan_Atilio disse:

      Boa tarde Eduardo.
      Um clique apenas nunca precisei, mas já tive que usar o duplo clique, então usei o método SetDoubleClick, passando um bloco de código que chama uma função estática dentro, por exemplo:

      oGetGrid:SetDoubleClick( {|| fSuaFuncao() } ) 
      
  5. Cristian Camillo Verneque disse:

    Boa tarde .. tudo bem??? você sabe se é possivel desabilitar a edição de uma linha no FwBrowse por uma determinada condição?? por exemplo: posso editar a linha se a legenda for VERDE e quando for VERMELHA nao editar nenhum campo?

    • Dan_Atilio disse:

      Bom dia Cristian, tudo sim graças a Deus e você?
      Olha, eu desconheço a existência de algum método assim nativamente.
      O que você pode fazer é na mudança de linha, na validação de linha, ou na edição da célula, você validar a condição da legenda.

  6. Marcos Abrahão disse:

    Bom dia Atílio, tudo bem?
    Mudei a chamada do FWExecView para (só quero abrir uma tela de consulta) :

    FWExecView(‘GRID Sem Cabeçalho’, “VIEWDEF.zGrid”, MODEL_OPERATION_VIEW, , { || .T. }, , ,aButtons )

    Mas assim o MVC não abre nada na tela, sabe porquê?
    Obrigado!!

    • Dan_Atilio disse:

      Bom dia Marcos, bem graças a Deus e você?
      Certo, no caso como está sua ViewDef dentro do fonte zGrid?
      Se o fonte e a User Function estiverem com outro nome, por exemplo, zDaniel, você tem que mudar também no ExecView, por exemplo, VIEWDEF.zDaniel.

  7. Robson disse:

    Bom dia Atílio, tudo bem?
    como faço para adicionar o campo de pesquisa?
    vi que tem a criação de índices, porem não exibe o campo de pesquisa pra selecionar o índice e info0rmar o conteúdo da pesquisa.

    • Bom dia Robson, tudo sim graças a Deus e você?
      Com FWBrowse, nunca precisei também, mas já fiz com FWMarkBrowse e suponho que deva ser o mesmo procedimento.
      Primeiro, você precisa de um array (vamos chamar de aSeek), que irá conter os índices que poderão ser pesquisados, e depois iremos usar o método SetSeek dentro do atributo oBrowse, ficando +- assim:

      //Para exemplo, caso precise, esses são os campos: aAdd(aSeek,{AllTrim(SX3->X3_TITULO)	,{{"",SX3->X3_TIPO,SX3->X3_TAMANHO, SX3->X3_DECIMAL,AllTrim(SX3->X3_TITULO),AllTrim(SX3->X3_PICTURE)}} } )
      
      aAdd(aSeek, {"Produto", {{"", "C", 15, 0, "Produto", "@!}} } )
      
      //...
      oBrowse:oBrowse:SetSeek(.T., aSeek)
      

Deixe uma resposta