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.
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.
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 ?
Grande Luizão, tudo joia?
Acho que sim, se forem criados dinamicamente, a única atenção é no TSay e TGet que eu crio no exemplo, eu a oDlgTst, ai você muda e coloca seu oFolder:aDialgos[nAba] no lugar.
Grande abraço jovem.
Chic Cara vou tentar e retorno aqui ok. Abraços e sucesso.
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.
Opa ai sim hein Luizão.
Grande abraço jovem.
E obrigado por compartilhar o resultado também.
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.
Amém.
Opa, bondade sua jovem.
Obrigado pelo comentário.
Grande abraço.
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.
encontré la forma de poder cambiar los datos dentro del tGet:
Lo que hay que hacer es definir antes el bloque de código, y luego con macro dentro de la definición del tget, por ejemplo:
cVaria := cGetCon + cValToChar(nY)
cBloque := “{|u| If(PCount() ==0, ” + cVaria + “, ” + cVaria + ” := u)}”
&(cSayObj + cValToChar(nY)) := TSay():New(065 + ((nY – 1) * 80),370,{||”Valor:”},oScrollB1,,,,,,.T.,0,16777215,070,010)
&(cGetCon + cValToChar(nY)) := 0
&(cGetObj + cValToChar(nY)) := TGet():New(065 + ((nY – 1) * 80),440,&(cBloque);
/*{|| &(“nGet” + alltrim(STR(nY))) }*/,oScrollB1,045,010,”@E 999,999,999.99″,{||VALCAN()},0,16777215,/*oFont*/,/*uParam12*/,/*uParam13*/,.T.,;
/*uParam15*/,/*uParam16*/,/*bWhen*/,/*uParam18*/,/*uParam19*/,/*bChange*/,/*lReadOnly*/.F.,/*lPassword*/.F.,/*uParam23*/,/*cReadVar*/cVaria,;
/**/,/**/,/**/,/**/)
Con esto pude asignar correctamente cada tget a su variable
Bom dia Marcelo.
Opa, excelente. Obrigado pela dica e contribuição no comentário.
Um grande abraço.