Interface Visual do AdvPL – Parte 02

Introdução

No post anterior, vimos alguns exemplos básicos de interface. Neste post, vamos ver uma tela usando vários componentes juntos, explorando mais possibilidades de uso. A diagramação da tela de exemplo praticamente não existe, os componentes não estão alinhados para uma apresentação visual perfeita, o objetivo do exemplo é puramente didático.

O exemplo

O fonte foi criado usando os comandos de interface, que por baixo vão chamar os construtores dos objetos visuais e seus métodos. Cada componente utilizado merece uma atenção especial, portanto neste post vamos avaliar o exemplo como um todo, e ver superficialmente o que cada componente utilizado permite fazer. Como o fonte deste exemplo ficou um pouco maior que os demais, ele estará disponível no link “APPInt02“, em formato “.doc”. O Blog não permite que eu suba arquivos fonte ou compactados, porém o fonte está inteiro dentro do arquivo, basta copiá-lo e colá-lo na tela do IDE/TDS para compilar e executá-lo. Ao ser compilado e executado diretamente pelo SmartClient, através da função U_APPINT02, o resultado de tela esperado pode ser visto abaixo:

APPINT02

Componentes utilizados

O container principal de interface usado neste exemplo foi uma tDialog(), ela será o pai de todos os demais componentes, e então o código cria todos os componentes “filhos” desta caixa de diálogo, e alguns containers para a disposição de mais elementos visuais.

@ … GROUP

O comando @ GROUP permite criar um componente de interface da classe tGroup(), com a finalidade de desenhar um quadrado ou retângulo na interface, opcionalmente com um título, para indicar visualmente que os componentes desenhados dentro da área do componente estão de alguma forma relacionados. Vale lembrar que o objeto tGroup() não é um container. Isto significa que, para colocar outro componente na área interna de um tGroup(), o componente visual deve ter o mesmo objeto pai do tGroup(), e usar o sistema de coordenadas do objeto pai. No nosso exemplo, dentro da área ocupada pelo tGroup foram colocados vários objetos de edição de dados de interface, todos a partir do oDlg (tDialog).

@ … SAY

O comando @ SAY permite criar um componente de interface da classe tSay(), com a finalidade de mostrar um texto na caixa de diálogo. Através dos parâmetros, informamos a coordenada esquerda superior onde o componente será desenhado, e o tamanho (comprimento,altura) reservados para a mensagem ser mostrada. Caso a mensagem a ser mostrada ultrapasse o comprimento do componente, haverá uma quebra de linha automática no texto da mensagem.

@ … GET

O comando @ GET permite criar um componente de interface da classe tGet(), com a finalidade de permitir a entrada e edição de dados pela interface. Podem ser editados campos do tipo C (Caractere), N (Numéricos) e D (Data). Para os campos caractere e numéricos, podemos especificar uma máscara (Picture), onde podemos especificar o formato que a informação será mostrada na tela e aplicar conversões automaticamente. Por exemplo, ao informarmos a picture “@!”, o componente automaticamente vai transformar cada caractere alfabético digitado para caixa alta (letra maiúscula), mesmo que você digite uma letra minúscula. Já a máscara numérica “999999999” vai permitir apenas a entrada de um número, com no máximo 9 dígitos, exclusivamente numéricos. Qualquer caractere não numérico digitado será ignorado.

@ … GET MULTILINE

Uma variação do @ GET foi implementada, usando a classe TMultiGet(), para permitir a edição de um conteúdo string em modo de múltiplas linhas, útil quando precisamos editar uma descrição de texto livre. Esta opção de edição não permite formatação, apenas quebra de linha usando a tecla [Enter], e tabulação usando [Control]+[I].

@ … CHECKBOX

O comando @ CHECKBOX permite criar um componente de interface da classe tCheckBox(), com a finalidade de editar um valor booleano, através de uma caixa de seleção do tipo “Check”, onde a variável associada ao componente receberá o valor .T. (verdadeiro) caso a caixa seja marcada, e .F. caso ela seja desmarcada.

@ .. COMBOBOX

O comando @ COMBOBOX permite criar um componente de interface da classe tComboBox(), com a finalidade de permitir escolher um item de um array de strings. O componente sempre mostra a escolha atual, e caso você clique na seta para baixo mostrada na frente da opção escolhida, é mostrado abaixo do componente a lista de opções disponíveis para a escolha. Ao escolher uma opção, a variável amarrada ao componente recebe a string contina no elemento do array escolhido.

@ .. LISTBOX

O comando @ LISTBOX permite criar um componente de interface da classe tListBox(), com a finalidade de permitir escolher um item de um array de strings. O componente sempre mostra em modo destacado a escolha atual, porém todas as opções possíveis são mostradas na área da tela parametrizada para o componente. Ao escolher uma opção, a variável amarrada ao componente recebe a string contida no elemento do array escolhido.

@ … FOLDER

O comando @ FOLDER permite criar um componente de interface da classe tFolder(), com a finalidade de criar um ou mais pastas dentro da área usada pelo componente, onde cada pasta possui um objeto interno para mostrar outros componentes de tela. Cada container de um folder é criado internamente, usando um objeto da classe tFolderPage, disponibilizado na propriedade aDialogs do objeto tFolder(). O primeiro elemento corresponde ao primeiro folder, o segundo elemento ao segundo folder, e assim sucessivamente. No exemplo proposto, foram colocados apenas um objeto tSay() dentro de cada Folder, para demonstrar sua funcionalidade. Lembrando que, como cada folder ué um container de elementos, as coordenadas dos componentes dentro de um folder partem do ponto esquerdo superior 0,0 de dentro do folder.

@ … MSPANEL

O comando @ MSPANEL permite criar um componente de interface da classe tPanel(), com a finalidade de servir de container para outros componentes de iterface. O Painel pode ter um efeito de destaque em suas bordas ( RAISED / LOWERED ), e outras propriedades de alinhamento que serão vistas com maior profundidade posteriormente. No fonte de exemplo, dentro do painel foi criado apenas um objeto tSay() para demonstração.

@ … RADIO

O comando @ RADIO utiliza internamente a classe TRadMenu(), e têm um funcionamento parecido com o componente LISTBOX, para múltipla escolha a partir de uma lista de possibilidades pré-definida. Porém, visualmente, a opção escolhida é marcada com um “Bullet” à esquerda do texto. Ao marcarmos uma nova opção, a opção anteriormente marcada é imediatamente desmarcada. E, a variável associada ao componente recebe um valor numérico, correspondente a opção marcada.

@ … SCROLLBOX

O comando @ SCROLLBOX permite criar um componente de interface da classe tScrollBox(), com a finalidade de desenhar um container com barra de rolagem horizontal ou vertical, para comportar outros componentes de interface. No nosso exemplo, reservamos uma área do diálogo para este componente, e desenhamos dentro dele dois tSay(), um no início da área util, visível na construção do componente, e um segundo tSay() em uma coordenada dentro do componente, onde ele somente será visivel caso seja utilizada a barra de rolagem do componente.

@ … METER

O comando @ METER cria uma barra horizontal de progresso, utilizando um objeto da classe tMeter(). Este objeto permite que seja setado um valor total de passos, correspondendo a 100 % da barra preenchida, e permite que durante a execução da aplicação, conforme o programa seja executado, o valor da posição atual na barra de progresso seja setado.

DEFINE BUTONBAR

Para uma caixa de diálogo, podemos criar uma barra de botões, alinhada no rodapé, no topo, ou às margens da caixa de diálogo. A barra de botões é uma instância da classe TBar(), que deve apenas conter botões com imagens, instâncias da classe TBtnBmp().

DEFINE BUTTON … BUTTONBAR

Na barra de botões criada pelo comando DEFINE BUTTONBAR, criamos botões dentro da barra usando este comando. Cada botão deve usar uma imagem, que pode estar compilada no repositório de objetos ou estar em um arquivo no disco. No exemplo proposto, foram usados algumas imagens disponíveis no repositório de objetos do ERP Microsiga versão 11.

@ … BTNBMP

Este comando cria um botão muito similar ao botão de uma barra de botões, para ser colocado livremente na interface, fora da barra de botões. Internamente, este componente usa a classe tBtnBmp2()

DEFINE SBUTTON

Existem 23 tipos de botões com imagem pré-definidos no AdvPL, ainda utilizados em fontes customizados de versões anteriores ao Protheus. Cada botão possui um identificador de tipo, onde para cada tipo uma imagem diferente é associada ao botão.

DEFINE TIMER

A classe tTimer() permite o disparo automático de um CodeBlock no servidor, a partir de uma caixa de diálogo ou janela, quando o controle de execução estiver no SmartClient,

Outros componentes

Ainda existem diversos componentes gráficos, desde a criação de gráficos até plotagem livre de interface (desenhar a interface), menus, árvores e afins. A utilização da Interface no AdvPL é um tema bem extenso, ainda estou estudando como desmembrá-lo nos próximos posts deste tema.

Todas as classes visuais do AdvPL estão documentadas na TDN, utilizadas na forma “direta”, isto é, através das chamadas explícitas de seus construtores, contendo os métodos e propriedades disponíveis para uso, esta documentação está disponível no link <>

Aspectos gerais do exemplo

Cada componente de entrada de dados normalmente está associado a uma variável local, que é atualizada pelo componente no momento que um novo valor é informado, e ocorre a perda de foco do componente, para foco em um próximo componente ativo na interface. Durante a digitação de um GET de uma variável caractere, numérica ou data, o valor da variável não é atualizado enquanto o valor está sendo digitado. Normalmente usamos a tecla para dar foco ao próximo componente ativo da interface, ou a tecla . E, para dar foco no componente anterior, usamos a combinação de teclas +. Podemos também trocar o foco com o mouse, simplesmente clicando em outro componente ativo para este ganhar foco.

Como uma caixa de diálogo, por default aceita a tecla como instrução de fechamento, esta caracteristica foi desligada, setando um valor .F. na propriedade lEscClose do objeto tDialog() para Falso (.F.). Ainda no exemplo proposto, é utilizado um objeto tTimer() para disparar um CodeBlock no servidor a cada 1 segundo, para incremento e atualização de uma barra de progresso (tMeter), onde foram definidos 1000 passos, e a cada atualização do timer, a posição atual do indicador de progresso é incrementado em uma unidade. Existe uma optimização interna no método de setagem de nova posição, que somente realiza o disparo de uma atualização de posição para a interface caso a nova posição na barra de progresso caso ela seja pelo menos uns 5% maior da última posição enviada ao SmartClient.

Também foi especificado um CodeBlock, para ser executado no momento do fechamento do diálogo. Caso você pressione + ou clique no “X” para fechar a caixa de diálogo, o CodeBlock é executado, e caso o retorno deste seja .T., o diálogo é fechado, caso contrário ele permanece aberto. Isto também vale caso você crie um botão com a chamada do método End() do objeto tDialog().

Em várias ações dos botões de interface, foram utilizadas as funçoes MsgInfo(), para mostrar uma caixa de diálogo com uma mensagem de texto, e a função GetClassName(), informando uma variável contendo um objeto da Interface. A função GetClassName() retorna uma string com o nome da classe pai deste objeto, e este retorno é mostrado na tela pela MsgInfo().

A troca de foco dos componentes quando navegamos por TAB ou SHIFT+TAB obedece a ordem de criação dos componentes. Logo, ao diagramar duas colunas de componentes de entrada de dados, de acordo com a ordem de criação você pode fazer o foco ir primeiro da esquerda para a direita, e então de cima para baixo, ou o contrário — primeiro o foco pega todos os componentes do lado esquerdo, de cima para baixo, para então cobrir os componentes da direita, de cima para baixo.

A interface no ERP Microsiga

Por baixo do Framework AdvPL do ERP Microsiga, são usados todos os componentes básicos da linguagem AdvPL deste exemplo, e os outros componentes ainda não abordados. Vários componentes de interface disponibilizados pelo FrameWork AdvPL do ERP Microsiga são heranças dos componentes básicos, e outros são componentes de mais alto nível, a partir de agrupamentos destes componentes. O MVC, por exemplo, permite o desenvolvimento de uma aplicação em AdvPL de um modo mais assistido, sem que você tenha que se preocupar com coordenadas de tela, as funções e classes por trás da implementação cuidam destes detalhes.

Normalmente usamos objetos tDialog() para montar interfaces complementares no ERP Microsiga, disparadas por pontos de entrada. Basicamente, um ponto de chamada é uma chamada de funções de usuário com nomes específicos em pontos determinados das rotinas do sistema padrão, para inferir modificações ou complementos ao seu comportamento. Quando queremos criar uma aplicação customizada no ERP, para ser chamada direto pelo SmartClient, e não como uma opção de Menu do ERP, utilizamos uma tWindow(), que permite controles adicionais.

Algumas boas práticas

Uma boa prática para a diagramação da interface, é agrupar os componentes que pertencem a uma determinada funcionalidade dentro de painéis, para alinharmos os componentes dentro do painel. Assim, caso seja necessário mover um grupo de componentes de lugar, como por exemplo em uma tela com uma barra vertical de botões auxiliares e um grupo de componentes de entrada de dados, caso seja necessário mudar a barra de botões do lado esquerdo para o direito da tela, apenas trocamos as coordenadas dos painéis, caso contrário teríamos que mexer no alinhamento de todos os componentes.

Combinando componentes

Como existem vários componentes que servem como container para outros componentes, caso você por exemplo precise que dentro de um dos seus folders caiba mais informações do que seu tamanho permite exibir, você pode criar um SCROLLBOX sem borda do tamanho do seu folder, e criar os componentes a partir do SCROLLBOX.

Conclusão

Longo é o caminho do desenvolvedor, cheio de possibilidades, mas proporcionalmente aprazível é ver a satisfação de seus clientes com um trabalho bem feito, duradouro, e construído de forma a atender a necessidade, projetado desde o alicerce para ser acessível, escalável e flexível.

Temos muitos posts pela frente, e é uma grande satisfação tê-los como leitores do “Tudo em AdvPL” ! Até o próximo post, pessoal 😉

15 respostas em “Interface Visual do AdvPL – Parte 02

  1. Siga0984 (Como não tem um nome pra te chamar né,hahaha)

    Obrigado por todos os posts até agora e todos que estão por vir!!

    É legal que mesmo ja sabendo fazer tudo que foi falado acima, o fato de você ler e entender melhor a Teoria do negócio, ao invez de copiar o bloco e alterar o necessário,ahhahaha

    Grande abraço!!

    Curtir

  2. BOA até que enfim alguém surgiu da cinza com uma boa aula de ADVPL, para fechar ou melhor para abrir com chave de ouro, teria como você criar uma agenda em advpl, com os seguintes dados, INCLUIR, EXCLUIR, ALTERAR. Tudo na customização, uns campos para digitar e um grird para visualizar e também digitar, parece simples mais tem tanta coisa ai nessa agenda que não tem a metade na net sobre isso ,olha que eu estou pesquisando no fundo do mar negro da net ksss e ainda com a opção de imprimir e mandar um e-mail nossa ai sim fica show, criando uma tabela no protheus meu caro Siga0984, isso vira um curso completo de ADVPL Customizado kssss

    Curtido por 1 pessoa

    • Opa, obrigado !! Ao longo dos posts, eu vou abordar ainda alguns assuntos isolados em maior profundidade, mas em um determinado momento chegaremos em um exemplo desse nível 😉

      Curtir

  3. Boa Tarde Júlio tudo bem?

    Parabéns pelo blog, o mesmo é excelente.

    Tenho uma dúvida; Eu como cliente Protheus, conseguiria criar um novo objeto visual em AdvPL, apenas utilizando as funções e classes disponibilizadas para nós clientes?

    Por exemplo, com as funções e classes disponíveis e conseguir criar um objeto parecido com o TGet, fazendo o “desenho” (retângulo) na tela e com a opção de imput de dados?

    Muito obrigado.

    Curtir

    • Você quer dizer, o preenchimento de um conteúdo em um objeto de interface ser obrigatório, é isso ? Eu acho que não, o que dá para fazer é usar, nos componentes que assim o permitem, uma validação na saída de foco do componente ( como o VALID do comando @…GET ), e/ou no botão usado para executar uma ação sobre os dados, o seu programa deve validar um a um se os campos considerados de preenchimento obrigatório foram preenchidos. 😉

      Curtir

  4. Olá Julio! Tudo certo?

    Primeiramente parabéns pelo teu blog! Muito conteúdo de qualidade desse universo Advpl!

    Sou iniciante nessa linguagem e com suas dicas muitas dúvidas acabam sendo sanadas. Obrigado!

    Mas quero abusar um pouco da sua gentileza….. Estou tentando desenvolver uma tela em MVC (Modelo 2), onde possuo uma tabela (customizada) que irá conter os dados do cabeçalho e dos itens em um mesmo registro (como se fosse o cadastro de Pedidos de Compra do Protheus), mas não estou conseguindo que ela se comporte da maneira correta. Ela gera o aHeader, mas não gera o aCols referente ao grid (que é o que permite preencher mais de um registro por vez.
    Você teria um exemplo completo de uma tela de cadastro MVC Modelo 2 para que eu possa me basear? Ou, se eu te passar o meu fonte, você consegue identificar onde estaria o erro?

    Curtido por 1 pessoa

    • Fala fera, beleza ? Então, meus conhecimentos no MVC do AdvPL são apenas “teóricos”…rs… Recomendo você dar uma olhada na documentação da TDN, e visitar/participar do fórum do HelpFácil AdvPL 😀

      Curtir

Deixe um comentário