Interface Visual do AdvPL – Parte 01

Introdução

A linguagem AdvPL permite a criação de programas com interface visual, com campos de entrada de dados, botões, labels, scroll (barra de rolagem), painéis e outros componentes visuais. Quando iniciamos a execução de uma aplicação através do aplicativo Smartclient, ele estabelece uma conexão TCP com o TOTVS Application Server, que faz a carga do programa solicitado do repositório de objetos do ambiente, e executa a aplicação AdvPL no servidor. Porém, todas as instruções de interface são enviadas ao SmartClient.

Introdução a interface visual

Primeiro, precisamos criar um componente principal de interface, digamos assim, o “pai de todos” os demais componentes. Normalmente criamos um objeto tWindow() ou tDialog() para isso. Os demais componentes visuais são criados, informando qual é o objeto do componente pai de cada um. No momento da criação de cada componente na memória do Application Server, durante a execução do programa AdvPL, é enviada uma mensagem do Application Server para o Smartclient, para a criação do respectivo componente na interface. Quando o programa AdvPL termina de criar os componentes, ele torna o onjeto pai dos componentes ativo, e isto transfere o controle de execução da aplicação para o SmartClient.

Assim, quando o componente pai é ativado, o SmartClient vai desenhar a tela e todos os componentes nela posicionados, e a execução do programa AdvPL permanece dentro do método de ativação do componente visual, aguardando que o usuário ou operador da aplicação executa alguma ação na interface, como por exemplo preencher um campo ou pressionar um botão de ação na interface.

Exemplo 01

Em outro tópico anterior, acredito que seja na orientação a objetos com herança de classe visual AdvPL, foi colocado um exemplo bem simples de uma caixa de díalogo, onde um dos botões da interface era criado a partir de uma classe compilada no repositório de objetos que herdava uma classe básica do objeto tButton da linguagem Advpl. O primeiro programa de “Hello World” de interfave será criado dentro desse molde, com uma mensagem estática na tela (tSay), e um botão para finalizar o objeto de interface.

#include 'protheus.ch'
User Function APPINT01()
Local oDlg
Local oBtn1, oSay1
 
DEFINE DIALOG oDlg TITLE "Exemplo" FROM 0,0 TO 150,300 COLOR CLR_BLACK,CLR_WHITE PIXEL
@ 25,05 SAY oSay1 PROMPT "Apenas uma mensagem" SIZE 60,12 OF oDlg PIXEL 
 
@ 50,05 BUTTON oBtn1 PROMPT 'Sair' ACTION ( oDlg:End() ) SIZE 40, 013 OF oDlg PIXEL
ACTIVATE DIALOG oDlg CENTER
Return

O resultado visual do programa acima, quando executado diretamente pelo SmartClient, deve ser este aqui:

appint01

Sistema de coordenadas

Vamos reparar em alguns pontos importantes do fonte acima. Primeiro, o componente principal da interface (pai de todos) é um objeto de diálogo, que eu queria que tivesse uma área útil interna de 300 pontos de comprimento por 150 de largura. Para isso, o diálogo foi criado através do comando DEFINE DIALOG, onde eu especifiquei as coordenadas 0,0 como ponto inicial (linha superior, coluna esquerda da tela), e as coordenadas finais 150,300 (linha inferior, coluna direita da tela). Para que no momento da ativação, este componente fosse centralizado na tela, eu usei o parâmetro “CENTER” na ativação do diálogo, feita pelo comando ACTIVATE DIALOG.

A criação do diálogo na prática chamou o construtor do objeto tDialog(), armazenando o objeto do componente criado na variável oDlg. E, a ativação do diálogo chamou o método Activate() do objeto tDialog(). E, como eu especifiquei um objeto de 300 x 150 pontos ( 300 pontos de comprimento por 150 de altura), o componente após montado vai ocupar um espaço maior que este, pois estes valores são interpretados como sendo a área interna útil em pontos (ou PIXELs) do componente.

Dentro deste tDialog(), eu coloquei um componente tSay(), para mostrar um texto, nas coordenadas 20,05 (linha,coluna), com um tamanho 60,12 (comprimento,altura). E, um pouco mais para baixo, nas coordenadas 50,05 (linha,coluna) eu coloquei um botão com tamanho 40,13 (comprimento,altura) com a ação de encerramento da interface principal — chamada do método End() do objeto tDialog().

Existem duas particularidades importantes sobre o sistema de coordenadas de componentes da interface. Primeiro, as coordenadas de um componente de interface s]ao sempre relativas às coordenadas 0,0 ( linha 0, coluna 0 ) da área útil do componente pai. Portanto, não importa onde o objeto tDialog() seja desenhado na tela, o objeto tSay() vai estar na coordenada 5,5 a partir da coordenada 0,0 de dentro da tDialog().

A segunda particularidade sobre o sistema de coordenadas de componentes é: As coordenadas informadas consideram o dobro da área útil em PIXELS do componente. Reparem que o componente tSay() foi criado na coordenada 25,05 (teoricamente 25 pixels pra baixo do ponto 0,0 de dentro da tDialog()), e o componente tButton() foi criado a partir da coordenada 50,05 (também teoricamente 50 pixels para baixo do ponto 0,0) da tDialog(). Se reparamos que a área interna do objeto tDialog() possui 150 pixels de altura, e o programa de testes cria componentes até no máximo a linha 50, o programa de exemplo deveria ocupar perto de 1/3 da altura do tDialog().

Porém, ao verificarmos o resultado em tela do programa, quase não sobrou nada na parte de baixo da tDialog(). Isso aconteceu devido as coordenadas de tela dos componentes, internamente, são multiplicadas por 2, tanto linha como coluna. Logo, quando informamos que o componente tSay() deve ser colocado na coordenada 20,05 , na verdade ele será desenhado a partir da coordenada 40,10 (40 pixels pra baixo, 10 pixels para a direita).

Cada componente de interface têm a sua coordenada de início no canto superior esquerdo. Logo, o botão desenhado a partir da coordenada 20,05 e com tamanho de 60,12 vai ser desenhado dentro da tDialog a partir da coordenada 40,10 , e vai terminar na coordenada 52,70 — basta somar as coordenadas de inicio “reais” com o comprimento e altura informados ao objeto.

Se eu não me engano, este comportamento do sistema de coordenadas foi mantido na linguagem AdvPL devido a código legado, que utilizava uma API que permitia utilizar os componentes de interface das primeiras versões do Windows.

Formas de escrever o fonte

Existem duas formas de endereçar os objetos da interface visual no AdvPL. Isto pode ser feito diretamente através dos construtores e métodos dos objetos de interface, documentados na TDN a partir do link (), ou através de comandos diretos — como foi feito no exemplo acima.

A utilização de comandos deixa o fonte mais compreensível, pois os objetos de interface possuem muitos parâmetros opcionais, e quando utilizamos a nomenclatura por comandos, nós somente endereçamos o que realmente é necessário ser informado no objeto. A leitura do código fica muito mais fácil. Porém, os comandos de interface ainda não foram oficialmente documentados.

Exemplo 02

O fonte do primeiro exemplo, escrito para utilizar diretamente os construtores e métodos dos componentes, ficaria da seguinte forma:

User Function APPINT02() 
Local oDlg
Local oBtn1, oSay1
 
oDlg = TDialog():New( 0, 0, 150, 300, "Exemplo" ,,,,, CLR_BLACK,CLR_WHITE ,,, .T. )
oSay1 := TSay():New( 25, 05, {|| "Apenas uma mensagem"} ,oDlg,,,,,,.T.,,, 60, 12 )
oBtn1 := TButton():New( 50, 05, "Sair", oDlg,{|| oDlg:End() }, 40, 013,,,,.T. )
oDlg:Activate( , , , .T. )
Return

Execução do código

Como eu havia mencionado anteriormente, no momento que ocorre a ativação do tDialog(), o TOTVS Application Server permanece na execução do método activate, aguardando por uma interação do usuário ou operador do aplicativo, para disparar alguma ação na interface, como por exemplo fechar a aplicação ou pressionar um botão.

No nosso exemplo, temos um botão que dispara uma ação no momento que o mesmo é acionado. Logo, ao clicarmos no botão, o SmartClient informa ao TOTVS Appplication Server que um botão foi pressionado, e o Application Server executa o bloco de código (ou CodeBlock) relacionado à ação de clique deste componente.

Esta ação pode chamar uma outra rotina, que cria e ativa uma nova caixa de dialogo, com outros componentes e botões, onde uma vez que esta caixa de diálogo esteja ativa, não é possível clicar em nenhum componente da caixa de diálogo anterior, que automaticamente deixa de receber foco com a ativação de uma nova tDialog.

Logo, qualquer comando ou função colocada dentro de um fonte, após o Activate() de uma tWindow() ou tDialog(), somente será executado quando esta janela ou diálogo for finalizado.

Capacidades da Interface

Através da linguagem AdvPL e aplicações sendo executadas através do SmartClient, podemos executar instruções de acesso a disco e arquivos (File I/O), portas e impressoras na estação onde o SmartClient está sendo executado. Podemos copiar arquivos da máquina onde está sendo executado o SmartClient para dentro de pastas a partir do rootpath (ou diretório raiz do ambiente), e vice-versa.

Restrições da Interface

Uma aplicação AdvPL não pode criar mais de uma tWindow(). Este objeto é “Highlander” (só pode haver um). A interface do ERP Microsiga conhecida por “SIGAMDI” cria apenas uma tWindow, e por baixo utiliza outros objetos para containers de seções independentes, onde cada seção ( ou “aba” ) da MDI pode ser executada em um servidor de aplicação diferente, onde existe um componente pai das abas de MDI, e cada componente filho é um container para a execução de uma aplicação em um contexto de conexão independente com o TOTVS Application Server, esses detalhes serão abortados em um outro post.

Existem componentes visuais que podem ser containers de outros componentes, para fins de alinhamento por exemplo, e existem componente não visuais ligados diretamente a interface, como também existem componentes de interface que não apresentam nada na interface ( tTimer() por exemplo). Como regra geral, um componente final de interface somente pode ter como componente pai um container. Caso isto não seja feito da forma correta, na melhor das hipóteses o componente apenas não será mostrado na interface, e na pior das hipóteses, pode ocorrer um erro de acesso inválido de memória ( Access Violation ou Segment Faut) no TOTVS Application Server, ou mesmo no próprio SmartClient.

Conclusão

Existem mais dicas e restrições, que vão aparecer no decorrer da abordagem deste assunto, e estes serão elucidadas e esclarecidas nos respectivos tópicos. Acho que para uma abordagem “inicial”, já temos bastante informações. Todos os componentes visuais do AdvPL estão documentados na TDN, existem recursos desde agrupamentos de componentes, painéis, pastas, grid, menus pop-up, drop-down, seleção múltipla, até um mini-editor de textos e um painel de desenho. Como eu disse no primeiro post desse blog, com AdvPL você pode fazer muita coisa, inclusive um ERP !!!

Nos próximos posts sobre a interface Visual do AdvPL, serão abordados exemplos usando alguns dos componentes principais e suas características, desde a utilização em programas de entrada de dados, e alguns exemplos um pouco mais rebuscados ! Vai ser divertido, eu garanto !

Até o próximo post, pessoal 😉

Anúncios

8 comentários sobre “Interface Visual do AdvPL – Parte 01

  1. O tema escolhido é ótimo, mas pode assustar quem esta começando e está acostumado com tudo pronto em outras linguagens rsrsrs. Parabéns pelo blog.

    Curtir

    • Quando interpretamos que a palavra “programação”, no contexto onde foi utilizada, refere-se ao conjunto de instruções de processamento, realmente usar drag-and-drop para codificar um algoritmo não me parece algo factível ou prático. Porém, a utilização de uma interface assistida de desenvolvimento, onde os objetos de processamento e interface possam ser manipulados e “amarrados” visualmente, acompanhado de um assistente de modelagem que permitisse incorporar algoritmos nos eventos e fazer a emissão do código final é um recurso muito, muito legal. Agradeço a menção do artigo no StackOverflow (Pt), no link https://pt.stackoverflow.com/questions/54752/por-que-drag-and-drop-para-programa%C3%A7%C3%A3o-%C3%A9-pouco-usado/55202#55202 , pelo meu amigo Luiz Vieira 😉

      Curtir

  2. Júlio você poderia abordar o tema redimensionamento de objetos de acordo com a resolução de tela?
    Redimensionar telas sempre foi um calcanhar de Aquiles para nós no quesito tempo e nos clientes que atendemos é um recurso bem precioso rsrsrs e isto aconteceu bastante quando acostumamos utilizar as coordenadas fixas em pixels e a diversidade de resoluções de tela a tratar sempre foi o complicador do processo (idem acontecia muito tb para impressão gráfica com TMsPrinter ).
    Se você tiver uma forma didática de exemplificar com estes objetos – MsMGet e uma MsGetDados (*ou MsNewGetDados) contida em um TFolder que é uma situação bem comum em várias rotinas padrão do sistema
    Com MVC isto melhorou muito mas acho q tem muito legado para trabalhar ainda

    Muito obrigado pelo conhecimento compartilhado 😉
    Abraço!!!

    Curtido por 1 pessoa

  3. Para quem trabalha com Java, Delphi e outras linguagens “visuais” a pouca documentação dos comandos de interface do ADVPL deixa qualquer programador desesperado. Mas aos poucos estou me acostumando a ter que garimpar as informações em códigos fontes de terceiros e poucos blogs de alta qualidade como este. Obrigado e parabéns Júlio.

    Curtido por 1 pessoa

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s