No vídeo de hoje, vamos demonstrar em como criar uma tela mobile usando apenas AdvPL sem utilizar outras tecnologias.
A dúvida de hoje, nos perguntaram, se seria possível usando exclusivamente o AdvPL, criar uma tela moldada ao padrão mobile, ou seja, sem usar PO UI, React, Angular, PHP com Bootstrap entre outros.
Claro que tem limitações, e o indicado é usar um front mais amigável e moderno, mesmo assim preparamos esse exemplo que usa puramente o AdvPL com orientação a objetos. A partir disso, definimos os objetos na tela e seus comportamentos.
Segue abaixo o vídeo exemplificando:
E abaixo o código fonte desenvolvido:
//Bibliotecas
#Include "TOTVS.ch"
/*/{Protheus.doc} User Function zVid0075
Função que abre uma tela mobile via programa inicial
@type Function
@author Atilio
@since 24/11/2023
@obs No appserver.ini, colque para já abrir direto via programa inicial, exemplo:
[WEBAPP]
Port=8099
HideParamsForm=1
LastMainProg=U_ZVID0075
EnvServer=AMBTST2
/*/
User Function zVid0075()
//Prepara o ambiente
If Select("SX2") <= 0
RPCSetEnv("99","01","daniel.atilio","tst123","","")
EndIf
//Aciona a montagem de tela
fMontaTela()
Return
Static Function fMontaTela()
Local aArea := FWGetArea()
//Tamanho da Janela e Comportamentos (centralizado)
Private aTamanho := GetScreenRes()
Private nJanLarg := aTamanho[1]
Private nJanAltu := aTamanho[2]
Private lCentered := .F.
//Fontes usadas pelos objetos
Private cFontPad := "Tahoma"
Private oFontTit := TFont():New(cFontPad, , -38)
Private oFontGrid := TFont():New(cFontPad, , -15)
//Objetos e variáveis da tela principal
Private oDlgMain := Nil
Private oPanGrid := Nil
Private oGetGrid := Nil
Private oBtnAlt := Nil
Private oSayTitulo := Nil
Private cSayTitulo := "Bem vindo -Usuário-"
Private aColunas := {}
//Estilo CSS dos botões
Private cCSSAzul := "TButton { font: bold; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #3DAFCC, stop: 1 #0D9CBF); color: #FFFFFF; border-width: 1px; border-style: solid; border-radius: 3px; border-color: #369CB5; }TButton:focus { padding:0px; outline-width:1px; outline-style:solid; outline-color: #51DAFC; outline-radius:3px; border-color:#369CB5;}TButton:hover { color: #FFFFFF; background-color : qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #3DAFCC, stop: 1 #1188A6); border-width: 1px; border-style: solid; border-radius: 3px; border-color: #369CB5; }TButton:pressed { color: #FFF; background-color : qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #1188A6, stop: 1 #3DAFCC); border-width: 1px; border-style: solid; border-radius: 3px; border-color: #369CB5; }TButton:disabled { color: #FFFFFF; background-color: #4CA0B5; }"
Private cCSSAmarel := "TButton { font: bold; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #000F00, stop: 1 #B4C00E); color: #FFFFFF; border-width: 1px; border-style: solid; border-radius: 3px; border-color: #B2B637; }TButton:focus { padding:0px; outline-width:1px; outline-style:solid; outline-color: #FDFD52; outline-radius:3px; border-color:#B2B637;}TButton:hover { color: #FFFFFF; background-color : qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #000F00, stop: 1 #A1A611); border-width: 1px; border-style: solid; border-radius: 3px; border-color: #B2B637; }TButton:pressed { color: #000; background-color : qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #A1A611, stop: 1 #000F00); border-width: 1px; border-style: solid; border-radius: 3px; border-color: #B2B637; }TButton:disabled { color: #FFFFFF; background-color: #B6B34D; }"
//Tabela temporária
Private cAliasTab
Private oTempTable
Private aFields := {}
//Define a tabela temporária
cAliasTab := GetNextAlias()
oTempTable := FWTemporaryTable():New(cAliasTab)
//Cria os campos
aFields := {}
aAdd(aFields, {"XXCODIGO", "C", 6, 0})
aAdd(aFields, {"XXDESCRI", "C", 30, 0})
aAdd(aFields, {"XXQUANTI", "N", 9, 2})
aAdd(aFields, {"XXEMISSA", "D", 8, 0})
aAdd(aFields, {"XXOBSERV", "C", 100, 0})
//Efetiva a criação da temporária e define um índice
oTempTable:SetFields(aFields)
oTempTable:AddIndex("1", {"XXCODIGO"} )
oTempTable:Create()
//Monta a estrutura das colunas exibidas na grid
fMontaHead()
//Popula a tabela temporária
fMontDados()
//Cria a janela sem o botão de fechar e sem ser possível sair pelo -ESC-
oDlgMain := TDialog():New(0, 0, nJanAltu, nJanLarg, "Teste Mobile", /*uParam6*/, /*uParam7*/, /*uParam8*/, DS_MODALFRAME, CLR_BLACK, RGB(250, 250, 250), , , .T.)
oDlgMain:lEscClose := .F.
//Mostra o título acima da grid
oSayTitulo := TSay():New(002, 002, {|| cSayTitulo}, oDlgMain, "", oFontTit, , , , .T., RGB(149, 179, 215), , (nJanLarg/2), 30, , , , , , .F., , )
//Monta um painel onde será exibido a grid da temporária
oPanGrid := tPanel():New(036, 002, "", oDlgMain, , , , RGB(000,000,000), RGB(254,254,254), (nJanLarg/2 - 3), (nJanAltu/2 - 75))
oGetGrid := FWBrowse():New()
oGetGrid:DisableFilter()
oGetGrid:DisableConfig()
oGetGrid:DisableReport()
oGetGrid:DisableSeek()
oGetGrid:DisableSaveConfig()
oGetGrid:SetFontBrowse(oFontGrid)
oGetGrid:SetAlias(cAliasTab)
oGetGrid:SetDataTable()
oGetGrid:AddLegend(cAliasTab + "->XXQUANTI == 0", "YELLOW", "Quantidade zerada")
oGetGrid:AddLegend(cAliasTab + "->XXQUANTI < 0", "RED", "Quantidade menor que zero")
oGetGrid:AddLegend(cAliasTab + "->XXQUANTI > 0", "GREEN", "Quantidade maior que zero")
oGetGrid:SetColumns(aColunas)
oGetGrid:SetOwner(oPanGrid)
oGetGrid:Activate()
//Cria o botão de Alteração
oBtnAlt := TButton():New((nJanAltu/2 - 72), 2, "Alterar", oDlgMain, {|| fAltera()}, (nJanLarg/2 - 3), 69, , oFontTit, , .T.)
oBtnAlt:SetCSS(cCSSAzul)
//Ativa a dialog
oDlgMain:Activate(, , , lCentered, {|| .T.}, , )
//Após fechar a dialog principal, apaga a temporária
oTempTable:Delete()
FWRestArea(aArea)
Return
Static Function fMontaHead()
Local nAtual
Local aHeadAux := {}
//Array com a estrutura de campos que será usada na grid
aAdd(aHeadAux, {"XXCODIGO", "Código", "C", 6, 0, "", .F.})
aAdd(aHeadAux, {"XXDESCRI", "Descricao", "C", 30, 0, "", .F.})
aAdd(aHeadAux, {"XXQUANTI", "Quantidade", "N", 9, 2, "@E 999,999.99", .T.})
aAdd(aHeadAux, {"XXEMISSA", "Emissão", "D", 8, 0, "", .T.})
aAdd(aHeadAux, {"XXOBSERV", "Observação", "C", 100, 0, "", .T.})
//Percorre o array e vem adicionando nas 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()
Local aArea := GetArea()
Local nAtual := 0
Local nTotal := 50
Local dDtRef := Date()
Local cCodAtu := "000000"
Local cDescri := ""
Local nQuanti := 0
Local dEmissa := sToD("")
//Percorre um valor de dados
For nAtual := 1 To nTotal
nAtual++
cCodAtu := Soma1(cCodAtu)
cDescri := "[" + Time() + "] Teste - " + cCodAtu
nQuanti := Randomize(-5, 5)
dEmissa := DaySub(dDtRef, nAtual)
//Inclui um registro na temporária conforme as variáveis
RecLock(cAliasTab, .T.)
(cAliasTab)->XXCODIGO := cCodAtu
(cAliasTab)->XXDESCRI := cDescri
(cAliasTab)->XXQUANTI := nQuanti
(cAliasTab)->XXEMISSA := dEmissa
(cAliasTab)->XXOBSERV := ""
(cAliasTab)->(MsUnlock())
Next
RestArea(aArea)
Return
Static Function fAltera()
//Variáveis e objetos usados na tela de alteração
Private oDlgAltera := Nil
Private nColMeio := (nJanLarg/2 - 3) / 2
Private oSayTitAlt, cSayTitAlt := "Alterar Registro"
Private oSayCodigo, oGetCodigo, cGetCodigo := (cAliasTab)->XXCODIGO
Private oSayDescri, oGetDescri, cGetDescri := (cAliasTab)->XXDESCRI
Private oSayObserv, oGetObserv, cGetObserv := (cAliasTab)->XXOBSERV
Private lConfirmou := .F.
//Cria a dialog de alteração
oDlgAltera := TDialog():New(0, 0, nJanAltu, nJanLarg, "Alteração", , , , , CLR_BLACK, RGB(250, 250, 250), , , .T.)
//Mostra um texto no cabeçalho
oSayTitAlt := TSay():New(002, 002, {|| cSayTitAlt}, oDlgAltera, "", oFontTit, , , , .T., RGB(149, 179, 215), , (nJanLarg/2), 30, , , , , , .F., , )
//Campo de código (que não será editável)
oSayCodigo := TSay():New(042, 002, {|| "Código:"}, oDlgAltera, "", oFontTit, , , , .T., , , (nJanLarg/2), 30, , , , , , .F., , )
oGetCodigo := TGet():New(072, 002, {|u| Iif(PCount() > 0 , cGetCodigo := u, cGetCodigo)}, oDlgAltera, (nJanLarg/2) - 4, 30, /*cPict*/, /*bValid*/, /*nClrFore*/, /*nClrBack*/, oFontTit, , , .T.)
oGetCodigo:lActive := .F.
//Campo de Descrição
oSayDescri := TSay():New(112, 002, {|| "Descrição:"}, oDlgAltera, "", oFontTit, , , , .T., , , (nJanLarg/2), 30, , , , , , .F., , )
oGetDescri := TGet():New(142, 002, {|u| Iif(PCount() > 0 , cGetDescri := u, cGetDescri)}, oDlgAltera, (nJanLarg/2) - 4, 30, /*cPict*/, /*bValid*/, /*nClrFore*/, /*nClrBack*/, oFontTit, , , .T.)
//Campo de Observação
oSayObserv := TSay():New(182, 002, {|| "Observação:"}, oDlgAltera, "", oFontTit, , , , .T., , , (nJanLarg/2), 30, , , , , , .F., , )
oGetObserv := TGet():New(212, 002, {|u| Iif(PCount() > 0 , cGetObserv := u, cGetObserv)}, oDlgAltera, (nJanLarg/2) - 4, 30, /*cPict*/, /*bValid*/, /*nClrFore*/, /*nClrBack*/, oFontTit, , , .T.)
//Botão Cancelar
oBtnCanc := TButton():New((nJanAltu/2 - 72), 2, "Cancelar", oDlgAltera, {|| oDlgAltera:End()}, nColMeio - 3, 69, , oFontTit, , .T.)
oBtnCanc:SetCSS(cCSSAmarel)
//Botão Confirmar
oBtnConf := TButton():New((nJanAltu/2 - 72), nColMeio + 3, "Confirmar", oDlgAltera, {|| lConfirmou := .T., oDlgAltera:End()}, nColMeio - 3, 69, , oFontTit, , .T.)
oBtnConf:SetCSS(cCSSAzul)
//Ativa a Dialog
oDlgAltera:Activate(, , , lCentered, {|| .T.}, , )
//Se foi clicado no botão confirmar, atualiza a tabela com o que o usuário escreveu
If lConfirmou
RecLock(cAliasTab, .F.)
(cAliasTab)->XXDESCRI := cGetDescri
(cAliasTab)->XXOBSERV := cGetObserv
(cAliasTab)->(MsUnlock())
EndIf
//Atualiza a grid da janela principal
oGetGrid:Refresh()
Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Parabéns pelo conteúdo.
Bom dia Everson, tudo joia?
Nós que agradecemos pelo comentário.
Tenha uma ótima e abençoada sexta feira.
Um grande abraço.
Ficou bacana daniel san, parabens pelo conteudo mestre……
Bom dia mister Patini, tudo joia?
Opa, obrigado pelo feedback, é bondade sua.
Tenha uma ótima e abençoada quinta feira.
Um grande abraço.