Clipper On Line • Ver Tópico - DIFICIL APRENDIZADO - Diálogos
Mudar para estilo Clássico
Discussão sobre a biblioteca Fivewin - O Clipper para Windows.
Postar uma resposta

DIFICIL APRENDIZADO - Diálogos

13 Out 2004 11:36

Amiguinhos

Em busca da interface perfeita, fico tentando variações de controles e posicionamentos diversos para criar um padrão para meu sistema, e com isto vou aprimorando o uso dos mesmos.

Neste tópico, baseado em uma opção de meu sistema, apresento juntamente com os arquivos necessários como produzir um diálogo sofisticado usando os controles 5Win como, dialog, listbox, page e o conceito de recursos embutidos.

Neste tópico voce aprenderá a manusear .RC que são arquivos textos contendo os parâmetros necessários para criação de diálogos e posicionamento de controles. Eles funcionam identicamente às DLLs com a diferença de serem linkados diretamente ao executável no final produzindo um aquivo apenas.

O primeiro passo é baixar o arquivo contendo os recursos necessários para o teste. Descompacte-os em uma pasta qualquer.

http://www.5volution.com.br/downloads/forum/forum5.zip

Vamos aos arquivos principais

O primeiro deles é o arquivo de recursos, o FORUM5.RC.

Ele possui definidas alguns diálogos que são:

TestBMPLbx - Diálogo principal
dlgAUX - Diálogo de suporte ao controle PAGE
dlgTADocto - Diálogo de suporte a tabela DOCTO
dlgTASiglas - Diálogo de suporte a tabela SIGLAS
dlgTAMensal - Diálogo de suporte a tabela MENSAL

Para abrir este arquivo e analisá-lo, basta usar o WorkShop.

Já o arquivo FORUM5.PRG contém partes interessantes que acho melhor explicá-las:

A listbox principal necessita de um vetor contendo os itens que farão o disparo da mudança de página do controle PAGE.

Código:
local aMenuItens := { "Documentos",;
                         "Siglas",;
                         "Mensalidades" }


Ao escolher um item dentro do listbox, o parâmetro ON CHANGE passa para o método oPags:SetOption() a posição numérica do item dentro do vetor usando a função ascan()
Código:
   REDEFINE LISTBOX cItem ;
            ON CHANGE oPags:SetOption(ascan(aMenuItens,cItem));
            ITEMS   aMenuItens ;


Logo no inicio do .PRG existe o comando SetHandleCount(150) que define a quantidade de arquivos que serão abertos na sessão do aplicativo e caso não seja definido obteremos erros de abertura de arquivo.
Código:
   SetHandleCount(150)


Não devemos esquecer de invocar a DLL padrão da Borland para que nossas diálogo sejam executadas, portanto no .PRG principal esta chamada deverá existir sempre.
Código:
   LoadLibrary("bwcc.dll")


Todas as tabelas utilizadas são abertas no modo SHARED e o parâmetro NEW ativa uma nova área de trabalho
Código:
   USE DOCTO    SHARED NEW INDEX DOCTO001,DOCTO002
   USE SIGLAS   SHARED NEW INDEX SIGLA019
   USE MENSAL   SHARED NEW INDEX MENSA001


Para que os controles tenham um apelo visual triidimensional ativamos o comando SET _3DLOOK ON

O diálogo principal é ativado e desenhado à partir da informações contidas no arquivo .RC e será chamado via parâmetro RESOURCE
Código:
   DEFINE DIALOG oDlg RESOURCE "TestBMPLbx"


O controle PAGE será redefinido com identificar 11 e ativará os diálogos de mesmo nome dlgAUX para todas as páginas definidas, já que as mesmas terão aparencia idêntica.
Código:
   REDEFINE PAGES oPags ID 11 OF oDlg DIALOGS "dlgAUX", "dlgAUX", "dlgAUX"


O passo principal de vinculo de cada listbox criada é redefini-la com a área da tabela já ativa, portanto, seleciono a tabela e redefino os controles não esquecendo de mudar as identificações dos controles para não obter erros, como oLbx1, oLbx2, aDialogs[1], aDialogs[3], etc.
Código:
   // **** Documentos ****
   SELE DOCTO
   REDEFINE LISTBOX oLbx1 FIELDS ID 600 OF oPags:aDialogs[1]
   REDEFINE BTNBMP ID 601 OF oPags:aDialogs[1] RESOURCE "bmp_plus"    TOOLTIP "Adiciona registro a tabela atual"   ACTION TabEDT( 1, oLbx1, "NOVO" )
   REDEFINE BTNBMP ID 602 OF oPags:aDialogs[1] RESOURCE "bmp_minus"   TOOLTIP "Exclui o registro da tabela atual"  ACTION TabDEL( 1, oLbx1)
   REDEFINE BTNBMP ID 603 OF oPags:aDialogs[1] RESOURCE "bmp_editar"  TOOLTIP "Altera dados do registro atual"     ACTION TabEDT( 1, oLbx1, "MOSTRA" )
   REDEFINE BTNBMP ID 604 OF oPags:aDialogs[1] RESOURCE "bmp_printer" TOOLTIP "Imprime o listagem da tabela atual" ACTION TabRPT( 1, oLbx1)
   oLbx1:nClrPane      := { || IIF( ( oLbx1:cAlias)->(OrdKeyNo()) %2 == 1, CLR_VERDINHO,CLR_CREME)}
   oLbx1:lAdjLastCol   := .F.
   oLbx1:nStyle        := 1
   oLbx1:nHeaderHeight*= 2

   // **** Siglas ****
   SELE SIGLAS
   REDEFINE LISTBOX oLbx2 FIELDS ID 600 OF oPags:aDialogs[2]
   REDEFINE BTNBMP ID 601 OF oPags:aDialogs[2] RESOURCE "bmp_plus"    TOOLTIP "Adiciona registro a tabela atual"   ACTION TabEDT( 2, oLbx2, "NOVO" )
   REDEFINE BTNBMP ID 602 OF oPags:aDialogs[2] RESOURCE "bmp_minus"   TOOLTIP "Exclui o registro da tabela atual"  ACTION TabDEL( 2, oLbx2)
   REDEFINE BTNBMP ID 603 OF oPags:aDialogs[2] RESOURCE "bmp_editar"  TOOLTIP "Altera dados do registro atual"     ACTION TabEDT( 2, oLbx2, "MOSTRA" )
   REDEFINE BTNBMP ID 604 OF oPags:aDialogs[2] RESOURCE "bmp_printer" TOOLTIP "Imprime o listagem da tabela atual" ACTION TabRPT( 2, oLbx2)
   oLbx2:nClrPane      := { || IIF( ( oLbx2:cAlias)->(OrdKeyNo()) %2 == 1, CLR_VERDINHO,CLR_CREME)}
   oLbx2:lAdjLastCol   := .F.
   oLbx2:nStyle        := 1
   oLbx2:nHeaderHeight*= 2


A função TabDEL apenas força a mudança de área para que não ocorra deleção de registros em uma tabela à partir de ação executada em outra tabela. Para os programadores mais experientes esta função poderá ser descartada pelo uso de funções mais diretas.
Código:
static function TabDEL( _num_, _lbx_ )
   do case
      case _num_ = 1
           SELE DOCTO
      case _num_ = 2
           SELE SIGLAS
      case _num_ = 3
           SELE MENSAL
   endcase
   if MsgYesNo( "Tem certeza da exclusao deste registro?" )
      RLOCK()
      DELETE
      COMMIT
      _lbx_:UpStable()
      _lbx_:Refresh()
   endif
   return .t.


A funcão TabRPT apresenta apenas um exemplo de obtenção de uma listagem à partir de uma tabela usando o comando REPORT, sendo de simples manuseio.
Código:
static function TabRPT( _num_, _lbx_ )
   local oRpt
   local n
   local cAlias := If( _lbx_ != nil, _lbx_:cAlias, Alias() )
   do case
      case _num_ = 1
      case _num_ = 2
           REPORT oRpt TITLE "Relatorio: " + cAlias ;
                 HEADER "Data: " + DToC( Date() ) + ", Hora: " + Time() ;
                 FOOTER "Pagina: " + Str( oRpt:nPage, 3 ) ;
                 PREVIEW
                 if Empty( oRpt ) .or. oRpt:oDevice:hDC == 0
                    return nil
                 endif
                 COLUMN TITLE "UF"      DATA SIGLAS->UF
                 COLUMN TITLE "ESTADO"  DATA SIGLAS->ESTADO
                 COLUMN TITLE "ICMS"    DATA SIGLAS->ICMS
                 COLUMN TITLE "IPI"     DATA SIGLAS->IPI
                 COLUMN TITLE "REDUCAO" DATA SIGLAS->REDUCAO
           ENDREPORT
           ACTIVATE REPORT oRpt
           GO TOP
      case _num_ = 3
   endcase
   return .t.


A função TabEDT irá acionar o diálogo de manutenção de registro da tabela escolhida pelo usuário.

Os seus parâmetros dependem do que for passado via botões no diálogo principal, sendo:
Código:
REDEFINE BTNBMP ID 601 OF oPags:aDialogs[1] RESOURCE "bmp_plus" ... ACTION TabEDT( 1, oLbx1, "NOVO" )
REDEFINE BTNBMP ID 603 OF oPags:aDialogs[1] RESOURCE "bmp_editar"  ... ACTION TabEDT( 1, oLbx1, "MOSTRA" )


Ou seja:

_num_ - É o número de pesquisa no DO...CASE
_lbx_ - o objeto oLbx? deve ser passado para que os métodos UpStable() e Refresh() sejam executados ainda dentro da função.
lAppend - Define o conteúdo das variáveis que serão manipuladas dentro do diálogo.
Código:
static function TabEDT( _num_, _lbx_, lAppend )
   do case
      case _num_ = 1
           tblDocto( _num_, _lbx_, lAppend )
      case _num_ = 2
           tblSiglas( _num_, _lbx_, lAppend )
      case _num_ = 3
           tblMensal( _num_, _lbx_, lAppend )
   endcase
   return .t.


A função tblMensal, que é a mais completa faço uso de diversos controles e a forma de seus conteúdos devem ser analisadas.

A saida do diálogo sem acréscimo de registros na tabela devem estar desligado pela variável lSave:
Código:
   local lSave := .f.


Dependendo do conteúdo de lAppend, as variáveis serão preenchidas de acordo

Aqui simulo um APPEND de TBrowse com registro em branco:
Código:
           if lAppend ="NOVO"
              goto bottom
              skip
           endif


Aqui dou um numero sequencial para o registro usando um arquivo de controle numérico:
Código:
           if lAppend ="NOVO"
              M->IDMENSAL := psqControle( dbf() )
           endif


Aqui defino a variável usada pelo CHECKBOX como sendo lógica:
Código:
           M->FIXA       := IIF(MENSAL->FIXA='S',.t.,.f.)


Aqui ativo o diálogo de manutenção de mensalidades
Código:
           DEFINE DIALOG oDlg RESOURCE "dlgTAMensal"


Aqui esta sendo redefinido um COMBOBOX com um vetor simples:
Código:
           REDEFINE COMBOBOX oCbx1 VAR M->TIPO ITEMS { "D-DESPESA", "R-RECEITA" } ...


Aqui utilizo uma função modificada para abertura de COMBO com tabelas, pois a DBCOMBO não trabalha com tabelas muito grandes:
Código:
           REDEFINE COMBO    oCbx2 VAR M->IDCCUSTO  ID 103 OF oDlg ;
                    RESOURCE "combo.bmp" ;
                    VALID    .T. ;           
                    ALIAS    CENTROS ;
                    ORDER    1  ;
                    FIELD    CENTROS->IDCCUSTO ;
                    HEADER   STR(CENTROS->IDCCUSTO,3),CCUSTO ;
                    RESULT   M->IDCCUSTO ;
                    UDF      fun()


Sendo que:

ALIAS - Nome da tabela em que os dados serão pesquisados
ORDER - Ordem de indice nesta tabela em que o dado será pesquisado
FIELD - Campo que terá o conteúdo retornado dentro da variável em RESULT
HEADER - Colunas que serão apresentadas no listbox de pesquisa.
RESULT - Variável que contém o resultado da busca.
UDF - função do usuário que será executada após ter escolhido o resultado.

Notem que as funções de manutenção das tabelas seguem um padrão:
Código:
   local lSave := .f.
    //
    // Aqui seleciono a tabela a ser manuseada
    //
    if lAppend ="NOVO"
       goto bottom
       skip
    endif
    //
    // Aqui as variáveis serão preenchidas com dados ou zeradas
    //
    if lAppend ="NOVO"
       //
       // No caso de inclusão, se alguma variável necessitar de dado padrão.
       //
    endif
    SET 3DLOOK ON
    DEFINE DIALOG oDlg ...
    //
    // Aqui são colocados todos os REDEFINEs de controles para o diálogo
    //
    REDEFINE BUTTON ID 1 OF oDlg ACTION ( lSave := .t. , oDlg:End() )
    REDEFINE BUTTON ID 2 OF oDlg ACTION ( lSave := .f. , oDlg:End() )
    ACTIVATE DIALOG oDlg CENTERED
    if lSave // Depende do resultado retornado pelo BUTTON acionado
       //
       // Aqui seleciono a tabela a ser manuseada
       //
       if lAppend ="NOVO"
          APPEND BLANK
       else
          RLOCK()
       endif
       //
       // Aqui salvo o conteúdo das variáveis em seus respectivos campos
       //
       COMMIT
       _lbx_:UpStable() // Devem existir sempre
       _lbx_:Refresh()
   endif
   return .t.


Por fim analisem o funcionamento da função psqControle, ela mantém em apenas um arquivo todos os numeros de controles de que necessitar.

Leiam também: viewtopic.php?t=874

@braços :?)
Postar uma resposta