Como criar vários TSay dinamicamente

No artigo de hoje, vamos mostrar como criar vários TSay de forma dinâmica em uma Dialog.

Antes de começarmos, essa dica foi enviada pelo grande o Súlivan Simões (LinkedIn).

Para quem já tentou criar inúmeros TSay (que basicamente são labels que podem ser usados na tela) dinamicamente, percebeu que alguns bugs e inconsistências podem acontecer.

Mesmo usando macro source com laço de repetição, o resultado não funciona adequadamente.

Mas então como podemos resolver essa questão? Bom, também usaremos macro source, mas para instanciar um novo TSay, e teremos que usar o método SetText para definir o conteúdo, abaixo o exemplo:

//Define o nome default dos say e a linha inicial que serão criados
cObjTSay := "oSayObj"
nLinha := 100

//Percorre de 1 a 10, criando os say, por exemplo, oSayObj1, oSayObj2, oSayObj3, etc
For nCont := 1 To 10
	&(cObjTSay + cValToChar(nCont)) := TSay():New(nLinha+=10, nMargem, {|| }, oDlg, , oFont, , , , .T., CLR_BLACK, , 200, 40, , , , , , .T.)
	&(cObjTSay + cValToChar(nCont)):SetText(cTexto)
Next

Update 03/06/2021:

Conforme a pergunta do internauta Fabricio Cardoso, eu fui testar a criação de TGets também dinamicamente, e eu só consegui fazer, acionando após criar a tela.

Então no bloco de código bInit, que é chamado após criar a tela que é feito o procedimento.

Eu preparei um código fonte de exemplo, onde é digitado em um parâmetro um valor de 1 a 9, e é criado automaticamente os TSay e TGet:

//Bibliotecas
#Include "TOTVS.ch"

/*/{Protheus.doc} User Function zTstObj
Função que testa a criação de objetos dinamicamente através de um For
@type  Function
@author Atilio
@since 03/06/2021
@version version
/*/

User Function zTstObj()
    Local aPergs   := {}
    Local nQuant   := 0
    
    //Adiciona no array de perguntas
    aAdd(aPergs, {1, "Qtde de Objetos (1 a 9)",  nQuant,  "@E 9",     "Positivo()", "", ".T.", 80,  .T.})
    
    //se a pergunta for confirmada cria a dialog
    If ParamBox(aPergs, "Informe os parâmetros", , , , , , , , , .F., .F.)
        If MV_PAR01 > 0
            fCriaTela()
        EndIf
    EndIf
Return

Static Function fCriaTela()
    Local bInit := {|| fCriaObj() }
    //Tamanho da janela
    Local nJanLarg := 400
    Local nJanAltu := 250
    //Inicio e fim do laço de repetição
    Local nAtual := 0
    Local nFinal := MV_PAR01
    //Objetos
    Private oDlgTst
    Private cSayObj := "oSay"
    Private cGetObj := "oGet"
    Private cGetCon := "cGet"
     
    //Cria as variáveis em memória (aqui mais um pulo do gato, é colocado o +1, para garantir que crie um a mais na memória e não dê erro ao instanciar os objetos)
    For nAtual := 1 To nFinal + 1
        SetPrvt(cSayObj + cValToChar(nAtual))
        SetPrvt(cGetObj + cValToChar(nAtual))
        SetPrvt(cGetCon + cValToChar(nAtual))
    Next

    //Cria a janela
    oDlgTst := TDialog():New(0, 0, nJanAltu, nJanLarg, 'Teste de Criação de Objetos', , , , , CLR_BLACK, RGB(250, 250, 250), , , .T.)
 
    //Ativa e exibe a janela
    oDlgTst:Activate(, , , .T., {|| .T.}, , bInit )
Return

//Foi necessário criar essa função no bInit, pois assim a tela já está "pré-criada" na memória, senão com TGet dava inconsistências na montagem dos dados
Static Function fCriaObj()
    Local nLinha := 3
    //Inicio e fim do laço de repetição
    Local nAtual := 0
    Local nFinal := MV_PAR01

    //Percorrendo de 1 até a posição digitada no parâmetro
    For nAtual := 1 To nFinal
        //Define o texto
        cTexto := "Linha " + cValToChar(nAtual)

        //Cria o TSay
        &(cSayObj + cValToChar(nAtual)) := TSay():New(nLinha, 003, {|| }, oDlgTst, , , , , , .T., CLR_BLACK, , 200, 40, , , , , , .T.)
        &(cSayObj + cValToChar(nAtual)):SetText(cTexto)
        &(cSayObj + cValToChar(nAtual)):lTransparent := .T.

        //Cria o TGet
        &(cGetCon + cValToChar(nAtual)) := cTexto
        &(cGetObj + cValToChar(nAtual)) := TGet():New(nLinha - 01, 53, {|| &(cGetCon + cValToChar(nAtual))}, oDlgTst, 100, 10, , , , , , , , .T., , , , , , , .T., , , , , , , , , , , , , , , , )

        nLinha += 12
    Next
Return

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.

11 Responses

  1. Fabricio Cardoso disse:

    Bom da Dan tudo bem??
    Achei massa esse artigo até porque o Súlivan tem em dado esse apoio e funcionou perfeitamente.
    Infelizmente não consegui ter o mesmo resultado com Tget. Se tiver alguma dica vai nos ajudar muito.
    Forte abraço e parabéns pelo conteúdo.

    • Opa, eae jovem, bem graças a Deus e você?
      Obrigado pelo feedback.
      Atualizei o artigo inserindo um exemplo, o pulo do gato para criar os TGet é acionar após a tela ter sido criada, então podemos fazer isso com o bloco bInit.
      Grande abraço.

  2. Luiz Alberto disse:

    Galera Salvaram minha vida, vou testar isso amanhã mesmo, porém tenho uma tela que na verdade não tem tsay e tgets diversos na mesma tela, mas em folders diferentes, tive varios bugs, será que com isso vou conseguir resolver em folders diferentes ?

  3. Luiz disse:

    Chic Cara vou tentar e retorno aqui ok. Abraços e sucesso.

  4. Luiz disse:

    Deu certo uhuuuuuuuuu, valeu rapaziada, como digo, ninguem sabe tudo, vivemos sempre aprendendo. Obrigado a Todos.

    cAcaoTSay := “oSayAcao”
    cDetaTSay := “oSayDeta”
    cRequTSay := “oSayRequ”
    cBotaSim := “oBSi”
    cBotaNao := “oBNa”

    For nPastas := 1 To Min(69,Len(aPastas))
    oFont := TFont():New(‘Tahoma’,24,24,,.T.,,,,.T.,.F.)

    oLogMAter := TBitmap():New( 220,570,70,070,,cLogoFOE,.F.,oFolder:aDialogs[nPastas],,,.F.,.T.,,””,.T.,,.T.,,.F. )
    oLogAllte := TBitmap():New( 005,005,40,030,,cLogoAll,.F.,oFolder:aDialogs[nPastas],,,.F.,.T.,,””,.T.,,.T.,,.F. )

    // Monta o Texto no formato HTML
    cTexto3 := ” + AllTrim(aSlide[nPastas,SLIDE_ATIVI]) + ‘ ‘ + AllTrim(aSlide[nPastas,SLIDE_NOMEM]) + ‘ ‘ + AllTrim(aSlide[nPastas,SLIDE_ORIEN]) + ”
    cTexto3 += ” + Iif(!Empty(aSlide[nPastas,SLIDE_MATPR]),AllTrim(aSlide[nPastas,SLIDE_MATPR])+’ – ‘+ AllTrim(aSlide[nPastas,SLIDE_CDCLI]) + ‘ – ‘ + AllTrim(aSlide[nPastas,SLIDE_DESCR]),”) + ”

    cTexto1 := ” + aSlide[nPastas,SLIDE_ACOES] + ”
    For nInsu := 1 To Len(aSlide[nPastas,SLIDE_INSUM])
    cTexto1 += ” + aSlide[nPastas,SLIDE_INSUM,nInsu,2] + ”
    Next

    cTexto1 += ”

    cTexto1 += ” + aSlide[nPastas,SLIDE_DETAL] + ”
    cTexto1 += ”
    cTexto1 += ” + aSlide[nPastas,SLIDE_OBSER] + ”

    cTexto2 := ” + aSlide[nPastas,SLIDE_REQUI] + ”

    //Define o nome default dos say e a linha inicial que serão criados

    &(cAcaoTSay + cValToChar(nPastas)) := TSay():New(005, 050, {|| }, oFolder:aDialogs[nPastas], , oFont, , , , .T.,, , 300, 50, , , , , , .T.)
    &(cAcaoTSay + cValToChar(nPastas)):SetText(cTexto3)

    &(cDetaTSay + cValToChar(nPastas)) := TSay():New(040, 010, {|| }, oFolder:aDialogs[nPastas], , oFont, , , , .T.,, , 200, 220, , , , , , .T.)
    &(cDetaTSay + cValToChar(nPastas)):SetText(cTexto1)

    &(cRequTSay + cValToChar(nPastas)) := TSay():New(230, 050, {|| }, oFolder:aDialogs[nPastas], , oFont, , , , .T.,, , 250, 200, , , , , , .T.)
    &(cRequTSay + cValToChar(nPastas)):SetText(cTexto2)

    &(cBotaSim + cValToChar(nPastas)) := TButton():New( 280, 200, “&Sim” ,oFolder:aDialogs[nPastas],{|| (U_AptoItem(cIdNadCap,1,oFolder)) }, 060, 020,,,.F.,.T.,.F.,,.F.,,,.F. )
    &(cBotaNao + cValToChar(nPastas)) := TButton():New( 280, 300, “&Não” ,oFolder:aDialogs[nPastas],{|| (U_AptoItem(cIdNadCap,0,oFolder)) }, 060, 020,,,.F.,.T.,.F.,,.F.,,,.F. )

    // AAdd(aSays,{cTexto1,cTexto2,cTexto3})

    @ 070, 430 BITMAP oBitmap1 SIZE 180, 130 OF oFolder:aDialogs[nPastas] FILENAME “” BORDER PIXEL

    cImgFile := aSlide[nPastas,SLIDE_IMAGE]
    cArqDest := SubStr(cImgFile,RAT(‘\’,cImgFile)+1,150)
    cArqDest := AllTrim(Right(Time(),2)+’_’+cArqDest)
    cTempArq := AllTrim(GetTempPath())+cArqDest

    If File(cTempArq)
    fErase(cTempArq)
    EndIf

    __CopyFile(cImgFile,cTempArq)

    oBitmap1:CBMPFILE := cImgFile
    oBitmap1:LSTRETCH := .T.
    //oBitmap1:bLDblClick := { || fVerImg() }
    //oBitmap1:LREADONLY := .T.
    oBitmap1:Refresh()
    Next
    oBSi1:SetFocus()
    Return .T.

  5. Fabricio Cardoso disse:

    Estou bem graças a Deus!!
    Funcionou perfeitamente o Tget com seu auxílio… vc é monstro!!
    Parabéns pelo trabalho meu amigo!!
    Um forte abraço.

  6. Luis disse:

    Alguém conseguiu fazer o TGET atualizando a variável? pois queria usar após clicar no botão salvar e gravar o dado.

    • Bom dia Luis.
      No caso eu tentei fazer, mas consegui apenas para visualização.
      Parece que na memória ao usar macro execução para criar os gets, ele dá uma bugada na memória.
      Tentei fazer direto no bInit, antes da criação da tela, e até após a criação.
      Grande abraço.

Deixe uma resposta