Cadastro poderoso usando classe

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

A do F9, pra quando digitar F9 fazer um browse do cadastro.

Código: Selecionar todos

STATIC FUNCTION Pesquisa()
   LOCAL xTela
   SAVE SCREEN TO xTela
   IF ReadVar() != "MCDCODIGO"
      RETURN NIL
   ENDIF
   dbEdit()
   IF LastKey() != K_ESC
      KEYBOARD Ltrim( Str( test->cdCodigo ) ) + Chr( 13 )
   ENDIF
   RESTORE SCREEN FROM xTela
   RETURN NIL
Nota: como só existe a variável MCDCODIGO em um único ponto do programa, só quando for esse nome é que o F9 funciona.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

Esta última, apesar de estar em uso em Execute(), no momento não faz nada.

Código: Selecionar todos

STATIC FUNCTION PodeAlterar()
   RETURN .T.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

Isso encerra a etapa de mostrar no estilo Clipper, usando variável PRIVATE e FUNCTION para tudo.
Apesar de tudo funcionando, é apenas um exemplo pra servir de base.
Cada um vai ajustar do jeito que achar melhor.

No momento, o importante é entender os diversos blocos/funções, pra entender na hora que virar uma classe.

Acho que podemos dizer que se copiarmos esse fonte pra tudo que é cadastro, e modificarmos a parte diferente, tá resolvido.

Está aí uma grande vantagem da classe: usando classe e herança, não precisamos copiar nada.
Só precisamos escrever o que for diferente.

Por enquanto o fonte como postado, no estilo Clipper/Harbour tradicional.
Quem quiser pode testar que funciona.
Anexos
test.zip
(1.8 KiB) Baixado 95 vezes
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

Estou alterando durante o post, por isso tem pausa.
Por exemplo, neste momento estou declarando a classe.
É um recurso normal dos editores de texto, "encolher" o código fonte pra determinados blocos, assim pude ver os nomes (os riscos representam partes "encolhidas".
Vejam que é praticamente copiar as declarações FUNCTION alterando pra METHOD, incluindo parâmetros, se existirem.

Nota: Comentei no início sobre estas alterações.
cadastro4.png
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

Agora indicar que pertencem à classe que chamei CadastroClass, acrescentando CLASS CadastroClass.
cadastro5.png
Agora preciso alterar cOpc para ::cOpc, e todas as chamadas pra funcionar dentro da classe, também colocando ::
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

Basicamente no programa principal mudou isto:

Código: Selecionar todos

   #include "hbclass.ch"
   ...
   LOCAL oFrm
   oFrm := CadastroClass():New()
   oFrm:Execute()
Não precisei mais declarar cOpc como PRIVATE, pois passou a fazer parte da classe.
E tudo aquilo passou a ficar dentro da variável oFrm.

Já dentro da classe, cOpc e funções que viraram métodos tiveram que receber ::
Apenas como exemplo, a Execute()

Código: Selecionar todos

METHOD Execute() CLASS CadastroClass
   IF .NOT. ::AbreArquivos()
      RETURN NIL
   ENDIF
   DO WHILE .T.
      ::TelaDados( .F. )
      ::MenuOpcoes()
      DO CASE
      CASE LastKey() == K_ESC
         EXIT
      CASE ::cOpc == "P" // Primeiro
         ::Primeiro()
         LOOP
      CASE ::cOpc == "U" // Ultimo
         ::Ultimo()
         LOOP
      CASE ::cOpc == "-" // Anterior
         ::Anterior()
         LOOP
      CASE ::cOpc == "+" // seguinte
         ::Seguinte()
         LOOP
      ENDCASE
      IF .NOT. ::cOpc $ "IAEC"
         LOOP
      ENDIF
      IF .NOT. ::Especifico()
         LOOP
      ENDIF
      ::TelaDados()
      IF ::cOpc == "C"
         LOOP
      ENDIF
      DO CASE
      CASE ::cOpc == "I" // inclui
         IF ::PodeAlterar()
            ::TelaDados( .T. )
         ENDIF
      CASE ::cOpc == "A" // Altera
         IF ::PodeAlterar()
            ::TelaDados( .T. )
         ENDIF
      CASE ::cOpc == "E" // Exclui
         IF ::PodeAlterar()
            ::Exclui()
         ENDIF
      ENDCASE
   ENDDO
   CLOSE DATABASES
   RETURN NIL
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

Tá... mas... e aí... tanto trabalho pra ficar igual... não mudou nada...
Fazer isso em todos os cadastros é só perda de tempo...
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

Agora vém a parte de usar isso pra tudo que é cadastro.
Olhando as rotinas, tem várias que serão iguais pra qualquer cadastro.
Somente 3 vão ser diferentes: AbreArquivos(), TelaDados() e Especifico().

O tradicional seria... copiar tudo e alterar essas 3 rotinas.

É aqui que a brincadeira fica legal: HERANÇA..... ou..... INHERIT.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

O novo fonte do cadastro, o primeiro bloco...

Código: Selecionar todos

#include "hbclass.ch"

PROCEDURE Cadastro1
   LOCAL oFrm
   oFrm := PrimeiroClass():New()
   oFrm:Execute()
   RETURN
Ué... mas PrimeiroClass() não é o nome da classe?
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

O segundo bloco, com o começo da classe:

Código: Selecionar todos

CREATE CLASS PrimeiroClass INHERIT CadastroClass
   METHOD AbreArquivos()
   METHOD TelaDados( lDigita )
   METHOD Especifico()
   END CLASS
Ué... não entendi nada....

Aqui está sendo criada a classe PrimeiroClass.
Essa classe recebe por herança (INHERIT) a classe CadastroClass.
Significa que todas as rotinas, TUDO que está na classe CadastroClass, agora também está na classe PrimeiroClass.
E não é só isso, estarei modificando estas três "rotinas".

Comparando:
No jeito tradicional, copia todo fonte, e altera o que for diferente.
Com classe, cria com herança, e altera o que for diferente.
Mesma coisa, sem copiar nada.

É só isso, e tudo isso.....

Como assim? É pouco ou é muito?

Vamos pensar nisso na prática:
Um sistema, principalmente de nota fiscal, tem dezenas de cadastros.
Vixi... De cara já é vantagem.... muito código fonte pode ser eliminado.
Converter fontes antigos então... economiza muito tempo, porque o fonte da sua classe estará testado e pronto pra uso.

E o que mais....

Quer alterar o menu de opções de todos os cadastros de uma vez?
Ele está na classe principal, só alterar a classe principal e pronto.

Quer alterar o menu de opções pra gráfico?
Só alterar a classe principal e pronto.

Quer alterar o menu pra parte de cima, ao invés da parte de baixo?
Aí temos que pensar...
Foi o que eu fiz...
Alterei TelaDados() e Especifico() pra usar Row() + 1 ( linha atual da tela + 1 )
Alterei a classe pra quando entrar nessas opções posicionar no lugar correto.
E por fim, alterei o menu da classe principal, pra botões gráficose parte de cima.
A única coisa que o menu precisa fazer é retornar a letra da opção, não importa como o menu faz isso.

E por aí vai.

Eu comecei a criar a classe pra cadastros, conforme fui fazendo fui vendo o que precisava a mais e fui ajustando.
Nos pedidos, por exemplo, vi necessidade de algo mais, porque nem sempre pode alterar um pedido.
No início do post mostrei uma função reserva: PodeAlterar()

Serve como um exemplo simples de uso, onde a herança nos pedidos cria uma PodeAlterar() própria:

Código: Selecionar todos

METHOD PodeAlterar() CLASS PedidoClass()
   IF pedido->Status == "N"
      Mensagem( "Não pode mexer em pedido com nota emitida" )
      RETURN .F.
   ENDIF
   IF UserLevel() < 1
      Mensagem( "Usuário não tem permissão de alterar pedido" )
      RETURN .F.
   ENDIF
   RETURN .T.
A mesma rotina simples de cadastro, usada pra digitação de pedidos, com checagem de nível de usuário e status de pedido.
Num caso desses, não vai deixar alterar ou excluir.

No caso dessa PodeAlterar(), o método original não fazia nada, mas a classe ficou pronta pra receber esse "adicional".

Basicamente é isso que uso, mas a minha classe tem muito mais coisas, que fui ajustando conforme fui usando para todo o sistema.
Por exemplo, nos pedidos, somente o menu básico não basta, acrescento mais opções no menu.

E acabei usando a classe básica até mesmo para um preview de impressão, pra navegar pelas páginas...

O limite é a imaginação.

E o negócio é não ter pressa.
Vai fazendo devagar, projetando com calma, e alterando um fonte de cada vez, sempre com calma.
Lembre-se que se mudar de idéia, por exemplo alterar o nome de TelaDados() pra outra coisa, terá que alterar todos os fontes que já tiver mexido,
Alterando um cadastro de cada vez vai confirmando se a classe atende ou se precisa de ajuste.

A que postei funciona, mas com certeza precisa ajuste na parte de inclusão, por exemplo, que já cadastra um registro com o código digitado.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

Pra ficar no post, a classe desse cadastro completa, que mostra como ficariam seus cadastros "normais":

Código: Selecionar todos

#include "hbclass.ch"

PROCEDURE Cadastro1
   LOCAL oFrm
   oFrm := PrimeiroClass():New()
   oFrm:Execute()
   RETURN

CREATE CLASS PrimeiroClass INHERIT CadastroClass
   METHOD AbreArquivos()
   METHOD TelaDados( lDigita )
   METHOD Especifico()
   END CLASS


METHOD AbreArquivos() CLASS PrimeiroClass
   LOCAL oStru
   IF .NOT. File( "test.dbf" )
      oStru := { { "CDCODIGO", "N", 6, 0 }, { "CDNOME", "C", 30, 0 } }
      dbCreate( "test", oStru )
   ENDIF
   IF .NOT. File( "test.cdx" )
      USE Test
      INDEX ON test->cdCodigo TAG "CODIGO"
      USE
   ENDIF
   USE test
   SET INDEX TO test
   RETURN .T.

METHOD TelaDados( lDigita ) CLASS PrimeiroClass
   LOCAL GetList := {}
   LOCAL mcdCodigo := test->cdCodigo
   LOCAL mcdNome   := test->cdNome
   lDigita := iif( lDigita == NIL, .F., lDigita )
   @ 2, 0 SAY "Codigo....:" GET mcdCodigo PICTURE "@K 999999" WHEN .F.
   @ 4, 0 SAY "Nome......:" GET mcdNome   PICTURE "@!"
   IF lDigita
      Mensagem( "Digite informações, <ESC> Sai" )
      READ
      Mensagem()
      IF LastKey() != K_ESC
         REPLACE test->cdNome WITH mcdNome
      ENDIF
   ELSE
      CLEAR GETS
   ENDIF
   RETURN NIL


METHOD Especifico() CLASS PrimeiroClass
   LOCAL GetList := {}
   LOCAL mcdCodigo := test->cdCodigo
   Mensagem( "Digite código, <ESC> Sai" )
   @ 2, 0 SAY "Codigo....:" GET mcdCodigo PICTURE "@K 999999" VALID mcdCodigo > 0
   READ
   Mensagem()
   IF LastKey() == K_ESC
      RETURN .F.
   ENDIF
   SEEK mcdCodigo
   IF ::CodigoInvalido()
      RETURN .F.
   ENDIF
   IF ::cOpc == "I"
      APPEND BLANK
      REPLACE test->cdCodigo WITH mcdCodigo
   ENDIF
   RETURN .T.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

Esqueci... tem o lado ruim.

Infelizmente, não tem checagem de variáveis e métodos de classe.

Se usar uma função que não existe, Minhoca(), o compilador dá erro que falta a função.

Mas se usar método de uma classe que não existe, o erro vai ser em tempo de execução.
oFrm:Minhoca()

A mensagem de erro vai ser algo parecido com: MESSAGE NOT FOUND
E pode acusar o erro na classe do cadastro: TestClass() por exemplo, no método Primeiro().
É bom lembrar que esse Primeiro() é da classe principal, e não da TestClass() - recebeu por herança.

É questão de ir acostumando com a novidade.

Aqui tinha feito um único fonte pra tudo.
Estou separando a classe, do cadastro, e do programa principal, pra enxergar melhor o que pertence a cada um.
Depois posto os fontes finais, incluindo um segundo cadastro ou terceiro... vamos ver até onde dá...
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Cadastro poderoso usando classe

Mensagem por JoséQuintas »

Deixei com dois cadastros.
Pra não fazer menu, depois de sair de um, entra no outro.
Acompanha fontes, arquivo hbp, DBFs com alguns cadastros de teste, e EXE compilado com Harbour 3.4 VSzakats

Rotina pesquisa ajustada pra funcionar com os dois arquivos, usando o campo chave de referência.

Estrutura totalmente diferente dos dois arquivos.

Test.prg - programa principal
CadastroClass.prg - Classe principal
Cadastro1.prg - Primeiro cadastro
cadastro2.prg - Segundo cadastro
test.dbf - primeiro arquivo
outro.dbf - segundo arquivo

Nota: não é a primeira vez que posto esse tipo de classe, mas desta vez foi com explicação detalhada, e com o equivalente sem usar classe.
Nota2: O fonte sem usar classe está nos primeiros posts
Anexos
test.zip
(394.61 KiB) Baixado 118 vezes
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
fladimir
Colaborador
Colaborador
Mensagens: 2445
Registrado em: 15 Nov 2006 20:21

Cadastro poderoso usando classe

Mensagem por fladimir »

Obrigado por compartilhar...

Já trabalhava com Classe mas nunca dominei, com tua explanação, clareou mais alguns pontos, obrigado, um dia fico bom nisso.

[]´s
Sun Tzu há mais de três mil anos cita nas epígrafes de seu livro “A Arte da Guerra“:

“Concentre-se nos pontos fortes, reconheça as fraquezas, agarre as oportunidades e proteja-se contra as ameaças”.
“Se não é vantajoso, nunca envie suas tropas; se não lhe rende ganhos, nunca utilize seus homens; se não é uma situação perigosa, nunca lute uma batalha precipitada”
.


Até 2017    Desktop Console [ Legado ] Harbour | MinGW | DBF | CDX | FastReport | MySQL


Novos Projetos:

   Desktop Visual           Windev Desktop
   Celular Android/iOS   Windev Mobile
   WEB                            Windev Web


Sejamos gratos a Deus.
Avatar do usuário
Toledo
Administrador
Administrador
Mensagens: 3133
Registrado em: 22 Jul 2003 18:39
Localização: Araçatuba - SP
Contato:

Cadastro poderoso usando classe

Mensagem por Toledo »

José Quintas, Fantástico... Parabéns, muito bem detalhado!

Obrigado por compartilhar!

Abraços,
Toledo - Clipper On Line
toledo@pctoledo.com.br
Harbour 3.2/MiniGui/HwGui
Faça uma doação para o fórum, clique neste link: http://www.pctoledo.com.br/doacao
Responder