No artigo de hoje, vamos demonstrar em como criar uma tela direto pelo programa inicial.
Pessoal, duas observações antes de iniciar o artigo:
- Para esse exemplo, é necessário baixar a zLogin (função que abre uma dialog para fazer login no Protheus) disponível em – https://terminaldeinformacao.com/2016/03/15/tela-de-autenticacao-customizada-protheus/
- Foi utilizado a classe MsNewGetDados apenas como exemplo, ela esta descontinuada, tente utilizar classes mais novas
No Protheus, nós temos dois tipos principais de janelas, as dialogs (TDialog, MsDialog, etc), e a janela principal (TWindow). A grande diferença delas, é que essa segunda se comporta como uma janela padrão do sistema operacional, ou seja com botões como maiximizar e minimizar.
Já a primeira, ela até pode ser aberta no programa inicial, mas existem algumas limitações.
Pensando nisso, construimos um fonte de exemplo para demonstrar em que, se o Protheus foi aberto a função direto no programa inicial (com u_zTstTela), ele usará a TWindow, agora se foi dentro do sistema usará a TDialog.
Em ambas usando os mesmos componentes e mesmo comportamento. Abaixo um gif demonstrando a abertura direto pelo programa inicial:
E abaixo o código fonte desenvolvido:
//Bibliotecas
#Include "TOTVS.ch"
/*/{Protheus.doc} User Function zTstTela
Tela de exemplo sendo possível acionar no programa inicial
@type Function
@author Atilio
@since 10/05/2022
/*/
User Function zTstTela()
Local lContinua := .T.
Local cEmprAux := "99"
Local cFilAux := ""
Private cUsrAux := ""
Private cPswAux := ""
Private lProgInic := .F.
//Se a SX2 não tiver aberta, quer dizer que não veio pelo Protheus, logo é quiosque
If Select("SX2")==0
//Montando uma seção, apenas para poder pegar os parâmetros da SX61
RPCSetEnv(cEmprAux, "", "", "", "")
//Verificando se o login deu certo
If u_zLogin(@cUsrAux, @cPswAux)
RPCSetEnv(cEmprAux, cFilAux, cUsrAux, cPswAux, "SIGAEST")
lContinua := .T.
lProgInic := .T.
Else
lContinua := .F.
EndIf
EndIf
If lContinua
fMontaTela()
EndIf
Return
Static Function fMontaTela()
Local nLinObj := 0
Local nLargBtn := 85
Local nAltuBtn := 15
//Blocos de código chamados pelos botões
Local bConfirm := {|| RptStatus({|| FWAlertInfo("Em Construção", "Atenção")}, "Processando Registros...", "Aguarde...")}
Local bCancela := {|| fCancelar()}
//Fontes
Private cFontPad := "Tahoma"
Private oFontBtn := TFont():New(cFontPad, , -14)
Private oFontBtnN := TFont():New(cFontPad, , -14, , .T.)
Private oFontMod := TFont():New(cFontPad, , -38)
Private oFontMaior := TFont():New(cFontPad, , -68)
Private oFontSub := TFont():New(cFontPad, , -20)
//Objetos da Janela
Private lCentered
Private oBtConfirm
Private oBtCancela
Private oSayTitulo, cSayTitulo := 'Tela de Testes'
Private oSayEtiqus, cSayEtiqus := '000'
Private oDlgCentral
//Tamanho da janela
Private aTamanho
Private nJanLarg
Private nJanAltu
Private nPosTop
Private nPosLeft
//Etiqueta
Private cEspacProd := Space(TamSX3("B1_COD")[1])
Private oGetProdut
Private cGetProdut := cEspacProd
Private oGetBlank
Private cGetBlank := ""
//Grid
Private oGridPro
Private aHeaderPro := {}
Private aColsPro := {}
//Se vier do programa inicial, a dimensão será diferente
If lProgInic
aTamanho := GetScreenRes()
nJanLarg := aTamanho[1]
nJanAltu := aTamanho[2] - 80
lCentered := .F.
nPosTop := 0
nPosLeft := -10
Else
aTamanho := MsAdvSize()
nJanLarg := aTamanho[5]
nJanAltu := aTamanho[6]
lCentered := .T.
nPosTop := 0
nPosLeft := 0
EndIf
//Cria o cabeçalho da grid
// Titulo Campo Picture Tamanho Dec Valid Usado Tipo F3
aAdd(aHeaderPro, {"Produto", "XX_PROD", "", 15, 0, ".F.", ".F.", "C", "", ""} )
aAdd(aHeaderPro, {"Descrição", "XX_DESC", "", 30, 0, ".F.", ".F.", "C", "", ""} )
aAdd(aHeaderPro, {"SB1 RecNo", "XX_RECNUM", "@E 999,999,999,999,999,999", 18, 0, ".F.", ".F.", "N", "", ""} )
aAdd(aHeaderPro, {" ", "XX_BLANK", "", 01, 0, ".F.", ".F.", "C", "", ""} )
//Cria a janela
If lProgInic
oDlgCentral := TWindow():New(nPosTop, nPosLeft, nJanAltu, nJanLarg, cSayTitulo, , , , , , , , CLR_BLACK, RGB(250, 250, 250), , , , , , , .T.)
Else
oDlgCentral := TDialog():New(nPosTop, nPosLeft, nJanAltu, nJanLarg, cSayTitulo, , , , , CLR_BLACK, RGB(250, 250, 250), , , .T.)
EndIf
//Títulos e SubTítulos
oSayTitulo := TSay():New(004, 003, {|| cSayTitulo}, oDlgCentral, "", oFontMod, , , , .T., RGB(149, 179, 215), , 200, 30, , , , , , .F., , )
oSayEtiqus := TSay():New(-003, (nJanLarg/2) - 120, {|| cSayEtiqus}, oDlgCentral, "", oFontMaior, , , , .T., RGB(255, 000, 000), , 100, 50, , , , , , .F., , )
//Get da Etiqueta
nLinObj := 36
oGetProdut := TGet():New(nLinObj, 3, {|u| Iif( Pcount()>0, cGetProdut := u, cGetProdut)}, oDlgCentral, (nJanLarg/2)-3, 20, "@!", {|| fVldCodig()}, , , oFontMod, , , .T., , , , , , , .F., , , , , , , , , , , , , , , , )
oGetProdut:cPlaceHold := "< Código do Produto >"
oGetBlank := TGet():New(-100, -100, {|u| Iif(PCount() > 0 , cGetBlank := u, cGetBlank)}, oDlgCentral, 10, 10, /*cPict*/, /*bValid*/, /*nClrFore*/, /*nClrBack*/, oFontBtn, , , .T.)
oGetBlank:bGotFocus := {|| oGetProdut:SetFocus()}
//Botões
nLinObj := 059
oBtConfirm := TButton():New(nLinObj + (nAltuBtn * 00), (nJanLarg/2) - (nLargBtn * 1), "Confirmar", oDlgCentral, bConfirm, nLargBtn, nAltuBtn, , oFontBtnN, , .T., , , , , , )
oBtCancela := TButton():New(nLinObj + (nAltuBtn * 01), (nJanLarg/2) - (nLargBtn * 1), "Cancelar", oDlgCentral, bCancela, nLargBtn, nAltuBtn, , oFontBtn, , .T., , , , , , )
//Abaixo cria a grid
oGridPro := MsNewGetDados():New(;
nLinObj,; //nTop
3,; //nLeft
(nJanAltu/2) - 3,; //nBottom
(nJanLarg/2) - 3 - nLargBtn,; //nRight
,; //nStyle
"AllwaysTrue()",; //cLinhaOk
,; //cTudoOk
"",; //cIniCpos
{},; //aAlter
,; //nFreeze
99999999,; //nMax
,; //cFieldOK
,; //cSuperDel
,; //cDelOk
oDlgCentral,; //oWnd
aHeaderPro,; //aHeader
aColsPro) //aCols
oGridPro:oBrowse:SetCSS(u_zCSSGrid())
oGridPro:lActive := .F.
//Ativa e exibe a janela
If lProgInic
oDlgCentral:Activate("MAXIMIZED")
Else
oDlgCentral:Activate(, , , lCentered, {|| .T.}, , )
EndIf
Return
Static Function fVldCodig()
Local lRet := .T.
Local aColsAux := oGridPro:aCols
Local lAdiciona := .T.
Local nPosProd := aScan(aHeaderPro, {|x| Alltrim(x[2]) == "XX_PROD"})
Local nLinha := 0
//Somente se tiver código de etiqueta
If ! Empty(cGetProdut)
//Validar se a etiqueta não foi inserida na grid ainda
For nLinha := 1 To Len(aColsAux)
If Alltrim(cGetProdut) == Alltrim(aColsAux[nLinha][nPosProd])
FWAlertError("O produto '" + cGetProdut + "' já foi adicionado na linha '" + cValToChar(nLinha) + "'!", "Falha")
lAdiciona := .F.
Exit
EndIf
Next
//Se deu tudo certo
If lAdiciona
DbSelectArea("SB1")
SB1->(DbSetOrder(1))
//Se conseguir posicionar no produto
If SB1->(MsSeek(FWxFilial('SB1') + cGetProdut))
//Se tiver apenas 1 linha e a coluna do produto estivar vazia
If Len(aColsAux) == 1 .And. Empty(aColsAux[1][nPosProd])
aColsAux := {}
EndIf
//Adiciona uma linha na grid
aAdd(aColsAux, {;
SB1->B1_COD,;
SubStr(SB1->B1_DESC, 1, 30),;
SB1->(RecNo()),;
"",;
.F.;
})
oGridPro:SetArray(aColsAux)
oGridPro:Refresh()
//Atualiza produtos lidos
cSayEtiqus := Soma1(cSayEtiqus)
oSayEtiqus:Refresh()
Else
FWAlertError("O produto '" + cGetProdut + "' não encontrado!", "Falha")
EndIf
EndIf
//Zera o Get, para ser inserida uma nova etiqueta
cGetProdut := cEspacProd
EndIf
Return lRet
Static Function fCancelar()
Local aColsAux := oGridPro:aCols
//Somente se a pergunta for confirmada
If FWAlertYesNo("Deseja cancelar?", "Continua?")
aColsAux := {}
oGridPro:SetArray(aColsAux)
oGridPro:Refresh()
cSayEtiqus := '000'
oSayEtiqus:Refresh()
EndIf
Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.

boa noite. Especificamente usando uma tdialog tem jeito de mesmo passando as coordenadas ela execute completamente maximizada na tela? Obrigado
Bom dia Mauricio, tudo joia?
Tanto a TDialog como TWindow, você pode abrir com a tela 100% cheia, desde que você acione no programa inicial (no lugar de SIGAMDI, SIGAADV, etc).
A partir do momento que você aciona dentro do Protheus, existem alguns limites (por causa da barra que fica acima com informações do usuário logado, por causa das abas que ficam abertas no SIGAMDI, etc).
Segue um exemplo de utilização da função MsAdvSize, que retorna as informações que podemos usar para criar uma dialog em tela cheia: https://terminaldeinformacao.com/2024/03/11/buscando-o-tamanho-do-monitor-com-getscreenres-e-msadvsize-maratona-advpl-e-tl-286/
Tenha uma ótima e abençoada sexta feira.
Um grande abraço.