Página 1 de 1

Classes e herança

Enviado: 10 Ago 2012 20:58
por JoséQuintas
Demorei um pouco pra entender a utilidade disso, principalmente herança.
Mas é sensacional.
Só imaginar classe como um conjunto de funções/variáveis, pra executar determinada tarefa.
E herança seria poder modificar uma função da classe, ou adicionar recursos/variáveis, etc.
Vou mostrar um relatório de clientes transformado em classe, e depois usar a herança pra modificar esse mesmo relatório pra imprimir produtos.
É nessa última hora que vemos como a herança é simples mas poderosa.

Este fonte eu fiz tudo num só PRG. Postando aqui em blocos só pra efeito de leitura.

A chamada dos relatórios é igual pra todos

Código: Selecionar todos

#include "hbclass.ch" 
Procedure Main

use jpcadas // clientes
Do Relatorio1
Do Relatorio2
Do Relatorio3
use jpitem // produtos
Do Relatorio4
Close Databases
Return
Primeiro o relatório básico

Código: Selecionar todos

Procedure Relatorio1
Local nLin, nPag

Set Printer To ("lixo1.txt")
Set Device To Print
nLin := 66
nPag := 0
Goto Top
Do While .Not. Eof()
   If nLin > 64
      @ 0, 0 Say "TITULO"
      @ 0, 132-7 Say "Pag." + StrZero(nPag,3)
      @ 1, 0 Say Replicate("-",132)
      nLin := 3
   Endif
   @ nLin, 0 Say jpcadas->cdCodigo
   @ nLin, pCol()+2 Say jpcadas->cdNome
   @ nLin, pCol()+2 Say jpcadas->cdEndereco
   nLin += 1
   Skip
Enddo
Set Printer To
Set Device To Screen
Run ("notepad.exe lixo.txt")
Return
Agora transformado em funções

Código: Selecionar todos

Procedure Relatorio2

cTxtFile := "lixo2.txt"
nLin := 66
nPag := 0
Set Printer To (cTxtFile)
Set Device To Print
Goto Top
Do While .Not. Eof()
   If nLin > 64
      Cabecalho(@nPag,@nLin)
   Endif
   Detalhe(@nLin)
   Skip
Enddo
Set Printer To
Set Device To Screen
ShowRelat(cTxtFile)

Function Cabecalho(nPag,nLin)
nPag += 1
@ 0,0 Say "Titulo"
@ 0,132-7 Say "Pag."+StrZero(nPag,3)
@ 1,0 Say Replicate("-",132)
nLin := 3
Return NIL

Function Detalhe(nLin)
@ nLin, 0 Say jpcadas->cdCodigo
@ nLin, pCol()+2 Say jpcadas->cdNome
@ nLin, pCol()+2 Say jpcadas->cdEndereco
nLin += 1
Return NIL

Function ShowRelat(cTxtFile)
Run ("notepad.exe " + cTxtFile)
Return NIL
Agora transformado em classe
Note que :: se refere a variáveis/funções locais da classe, usava Self: no começo, mas com :: o código fica mais legível.

Código: Selecionar todos

Procedure Relatorio3

Relatorio():Execute("lixo3.txt")
Return NIL

Create Class Relatorio
   Data nLin
   Data nPag
   Data cTxtFile
   Method Cabecalho()
   Method Detalhe()
   Method Execute()
   Method ShowRelat()
   EndClass

Method Cabecalho() Class Relatorio
   ::nPag += 1
   @ 0, 0 Say "Titulo"
   @ 0, 132-7 Say "Pag."+StrZero(::nPag,3)
   @ 1, 0 Say Replicate("-",132)
   ::nLin := 3
   Return NIL
   
Method Detalhe() Class Relatorio
   @ ::nLin, 0 Say jpcadas->cdCodigo
   @ ::nLin, pCol()+2 Say jpcadas->cdNome
   @ ::nLin, pCol()+2 Say jpcadas->cdEndereco
   Return NIL

Method ShowRelat() Class Relatorio
   Run ("notepad.exe " + ::cTxtFile)
   Return NIL

Method Execute(cTxtFile) Class Relatorio
   Set Printer To (cTxtFile)
   Set Device To Print
   ::cTxtFile := cTxtFile
   ::nLin := 66
   ::nPag := 0
   Goto Top
   Do While .Not. Eof()
      If ::nLin > 64
         ::Cabecalho()
      Endif
      ::Detalhe()
      ::nLin += 1
      Skip
   Enddo
   Set Printer To
   Set Device To Screen
   ::ShowRelat()
   Return NIL
Agora o uso da classe com herança usada para produtos ao invés de clientes
Note que a classe nova foi criada a partir da anterior, só foi modificado o método Detalhe(), que é o que interessa modificar.

Código: Selecionar todos

Procedure Relatorio4

RelatorioProduto():Execute("lixo4.txt")

Create Class RelatorioProduto INHERIT Relatorio
   Method Detalhe()
   EndClass
   
Method Detalhe()
   @ 0, 0 Say jpitem->ieItem
   @ 1, pCol()+2 Say jpitem->ieDescri
   Return NIL
A principal vantagem é pegar algo que funcione e modificar somente o que interessa.
A classe de relatório funciona, então alterando só o detalhe vai continuar funcionando.
Notem como o fonte 4 ficou pequeno. É a partir daí que valeu a pena o trabalho.
A mesma classe poder ser usada pra qualquer arquivo, e qualquer layout.

Considerações:
- "#include hbclass.ch" é necessário onde se cria a classe. No fonte que apenas usa classe pronta não é necessário.
- Dentro da criação da classe é necessário colocar os nomes dos métodos
- Nos métodos, necessário colocar o nome da classe a que se refere
- Quando a classe usa alguma variável ou função dela mesma, necessário usar Self:nome ou ::nome
- No caso do último fonte, a classe herda a anterior, então a outra classe precisa estar linqueditada junto.
- Esta classe de relatório é só um simples exemplo. Não serve pra uso normal, porque faltam os títulos das colunas. Mas testei antes de postar, e todos funcionam.

Acaba sendo mais interessante do que ficar usando macros, ou funções que se complicam cada vez mais.
O fonte de classe fica mais organizado e fácil de entender, depois que se pega o jeito.

Classes e herança

Enviado: 10 Ago 2012 22:08
por ANDRIL
JoséQuintas escreveu:Demorei um pouco pra entender a utilidade disso, principalmente herança.
Mas é sensacional.
José ótima explicação, simples e direta. Valeu!

Classes e herança

Enviado: 11 Ago 2012 22:41
por JoséQuintas
Faltou só uma coisinha pra completar:
Se na classe "pai de todas" alterar o cabeçalho, já altera todos os relatórios do sistema de uma vez.

Aqui passei a fazer relatórios nesse estilo. Depois fui alterando a classe pra permitir escolher PDF retrato, PDF paisagem e matricial (tem cliente usando). O relatório já se ajusta em linhas/colunas conforme o formato de saída, uma vez que faz uso da classe.
É alterar todos os relatórios de uma vez, só mexendo na classe principal.
Também deixei as opções do menu na classe, sobre os tipos de impressão. Se inventar um PDF de diagonal, é so mexer na classe, e a opção vai aparecer na tela de todos os relatórios.

E pra resolver problemas de impressão.... por exemplo selecionar impressora nos relatórios... só mexer na classe.
Obs. No meu caso, pelo menos por enquanto, só criei uma classe pra relatórios, não precisei subclasse.

Classes e herança

Enviado: 12 Ago 2012 19:07
por fladimir
Obrigado colega clareou bastante...

[]´s

Classes e herança

Enviado: 13 Ago 2012 14:51
por alxsts
Olá!

A OOP, como a maioria das coisas que existem, tem seus prós e contras. Mas, sem dúvida, é uma técnica muito legal mesmo. Dá para fazer coisas sensacionais com ela, inclusive implementar novas funcionalidades nas classes padrão da linguagem e até estender os tipos de dados existentes.

Vejam o código abaixo, extraído do manual do xHarbour(xHarbour Language Reference Guide.chm). Neste exemplo, o tipo de dados Date é estendido, ganhando novos recursos de formatação:

Código: Selecionar todos

// The example implements a class that extends the data type
// Date with advanced date and time formatting capabilities.
// It distinguishes upper and lower case letters for the Day,
// Month and time. A formatting template is built with the
// following characters:
//
// d    - numeric day without leading zero
// dd   - numeric day with leading zero
// ddd  - numeric day without leading zero and postfix (st, nd, rd, th)
// D    - first letter of weekday
// DD   - name of weekday abbreviated to two characters
// DDD  - name of weekday abbreviated to three characters
// DDDD - complete name of weekday
// M    - numeric month without leading zero
// MM   - numeric month with leading zero
// MMM  - month name abbreviated to three letters
// MMMM - complete month name
// yy   - year without century
// yyyy - year with century
// h    - hour without leading zero
// hh   - hour with leading zero
// m    - minute without leading zero
// mm   - minute with leading zero
// s    - second without leading zero
// ss   - second with leading zero
// \    - escape character for d, D, m, M, y, h, m, s

   #include "HbClass.ch"   

   PROCEDURE Main
      LOCAL dDate

      ASSOCIATE CLASS DateFormatter WITH TYPE DATE

      dDate := Ctod( "09/01/2006" )

      ? dDate               
      // result: 09/01/06

      ? dDate:shortDay()
      // result: Fri

      ? dDate:shortMonth()
      // result: Sep

      ? dDate:format( "dd MMM. yyyy" )
      // result: 01 Sep. 2006

      ? dDate:format( "dd-MM-yy hh:mm\h", Time() )
      // result: 01-09-06 18:07h

      dDate += 2

      ? dDate:format( "DDDD, MMMM ddd, at h \hour\s an\d m \minute\s" )
      // result: Sunday, September 3rd, at 18 hours and 7 minutes

      ? dDate:httpDate()
      // result: Sun, 03 Sep 2006 18:07:45
   RETURN


   CLASS DateFormatter
      EXPORTED:
      METHOD shortDay   INLINE Left( CDow(self), 3 )
      METHOD shortMonth INLINE Left( CMonth(self), 3 )
      METHOD time       INLINE Time()
      METHOD asString   INLINE DtoS(self)
      METHOD httpDate
      METHOD format
   ENDCLASS


   METHOD httpDate( cTime ) CLASS DateFormatter
   RETURN ::format( "DDD, dd MMM yyyy hh:mm:ss", cTime )


   METHOD format( cFormat, cTime ) CLASS DateFormatter
      LOCAL aToken := {}
      LOCAL cToken := ""
      LOCAL cChar

      IF cTime == NIL
         cTime := ::time()
      ENDIf

      FOR EACH cChar IN cFormat
         IF .NOT. cChar IN "DdMyhms"
            IF Len( cToken ) > 0
               AAdd( aToken, cToken )
            ENDIF
            IF cChar == "\"
               cToken := cChar
            ELSE
               AAdd( aToken, cChar )
               cToken := ""
            ENDIF
         ELSE
            cToken += cChar
         ENDIF
      NEXT
      AAdd( aToken, cToken )

      cFormat := ""
      FOR EACH cToken IN aToken
         IF cToken == ""
            LOOP
         ENDIF

         SWITCH cToken[1]
         CASE "y"
            IF Len( cToken ) == 4
               cFormat += Left( ::asString(), 4 )
            ELSE
               cFormat += SubStr( ::asString(), 3, 2 )
            ENDIF
            EXIT

         CASE "M"
            SWITCH Len( cToken )
            CASE 1
               cToken := SubStr( ::asString(), 5, 2 )
               IF cToken[1] == "0"
                  cFormat += cToken[2]
               ELSE
                  cFormat += cToken
               ENDIF
               EXIT
            CASE 2
               cFormat += SubStr( ::asString(), 5, 2 )
               EXIT
            CASE 3
               cFormat += ::shortMonth()
               EXIT
            DEFAULT
               cFormat += CMonth(self)
            END
            EXIT
            
         CASE "D"
            IF Len( cToken ) <= 3
               cFormat += Left( CDoW(self), Len(cToken) )
            ELSE
               cFormat += CDoW(self)
            ENDIF
            EXIT

         CASE "d"
            SWITCH Len(cToken)
            CASE 1
               cToken := Right( ::asString(), 2 )
               IF cToken[1] == "0"
                  cFormat += cToken[2]
               ELSE
                  cFormat += cToken
               ENDIF
            CASE 2
               cFormat += Right( ::asString(), 2 )
               EXIT
            DEFAULT
               cToken := Right( ::asString(), 2 )
               cFormat += IIf( cToken[1] == "0", cToken[2], cToken )

               DO CASE
               CASE cToken == "11" .OR. ;
                    cToken == "12"   ; cFormat += "th"
               CASE cToken[2] == "1" ; cFormat += "st"
               CASE cToken[2] == "2" ; cFormat += "nd"
               CASE cToken[2] == "3" ; cFormat += "rd"
               OTHERWISE
                  cFormat += "th"
               ENDCASE
            END
            EXIT

         CASE "h"
         CASE "m"
         CASE "s"
            SWITCH cToken[1]
            CASE "h" ; cChar := Left  (cTime,2)   ; EXIT
            CASE "m" ; cChar := SubStr(cTime,4,2) ; EXIT
            CASE "s" ; cChar := Right (cTime,2)   ; EXIT
            END

            IF Len( cToken ) == 1 .AND. cChar[1] == "0"
               cChar := cChar[2]
            ENDIF
            cFormat += cChar
            EXIT

         CASE "\"
            cFormat += SubStr( cToken, 2 )
            EXIT

         DEFAULT
            cFormat += cToken
         END
      NEXT
   RETURN cFormat

Classes e herança

Enviado: 01 Set 2012 19:18
por JoséQuintas
Gostei disso. Já deixa funções de data vinculadas ao tipo date(). Vou testar no Harbour.

Classes e herança

Enviado: 02 Set 2012 06:19
por JoséQuintas
Tava brincando com um programinha antigo em clipper, e transformei em classe.
Por enquanto foi só teste: uma classe pra fazer todos os cadastros.
No fonte tem:
- A classe genérica, que seria a base pra tudo
- A classe herdada, para o cadastro de clientes
- O programa que faz uso da classe

A estrutura do arquivo usado é um cadastro básico, todos os campos string, com CDCODIGO(6), CDNOME(30), CDENDERECO(30), CDCIDADE(15), CDUF(2), CDCEP(8), sendo que o único tamanho obrigatório pra funcionar é o código com 6 dígitos.
Todo uso é pelo mouse, e e só compilar normal com hbmk2 programa
É um visual simples, que precisa ser melhorado, mas tá funcionando.

Código: Selecionar todos

#include "getexit.ch"
#include "inkey.ch"
#include "hbclass.ch"

*----------------------------------------------------------------
// programa principal

Procedure Main
   Request SIXCDX
   RddSetDefault("SIXCDX")
   Use \jpa\cordeiro\jpcadas
   Set Index To \jpa\cordeiro\jpcadas
   OrdSetFocus("numlan")
   SetColor("W/N,N/W,,,W/N")
   Set( _SET_EVENTMASK, INKEY_ALL ) // + HB_INKEY_GTEVENT 
   Tela := CadastroCliente()
   Tela:Execute()

*----------------------------------------------------------------
// Classe especifica pra cliente

CREATE CLASS CadastroCliente INHERIT CadastroGenerico
   Data cNome               INIT " "
   Data cEndereco           INIT " "
   Data cCidade             INIT " "
   Data cUf                 INIT " "
   Data cCep                INIT " "
   Method cmdSalvaClick(oGet)
   Method SetKeyField(cValue)
   Method SetFields(lBlank)
   Method Execute()
   EndClass

Method cmdSalvaClick(oGet) Class CadastroCliente
   If ::cCodigo == "*NOVO*"
      Goto Bottom
      ::cCodigo := StrZero(Val(jpcadas->cdCodigo)+1,6)
      Append Blank
      Replace jpcadas->cdCodigo With ::cCodigo
   Endif
   rLock()
   Replace ;
         jpcadas->cdEndereco With ::cEndereco, ;
         jpcadas->cdCidade With ::cCidade, ;
         jpcadas->cdUf With ::cUf, ;
         jpcadas->cdCep With ::cCep
   Skip 0
   Unlock   
   ::Reload()
   ::EditKeyEnabled     := .f.
   ::EditFieldsEnabled  := .f.
   ::EditCmdEnabled     := .f.
   ::NavegateCmdEnabled := .t.
   oGet:ExitState := GE_TOP
   Return NIL

Method SetKeyField(lEmpty) Class CadastroCliente // Pega chave
   lEmpty := iif(lEmpty==NIL,.f.,lEmpty)
   If lEmpty
      ::cCodigo := Space(6)
   Else
      ::cCodigo := jpcadas->cdCodigo
   Endif
   Return NIL
   
Method SetFields(lEmpty) Class CadastroCliente // Pega campos
   lEmpty := iif(lEmpty==NIL,.f.,lEmpty)
   If lEmpty
      ::cCodigo   := "*NOVO*"
      ::cNome     := Space(Len(jpcadas->cdNome))
      ::cEndereco := Space(Len(jpcadas->cdEndereco))
      ::cCidade   := Space(Len(jpcadas->cdCidade))
      ::cUf       := Space(Len(jpcadas->cdUf))
      ::cCep      := Space(Len(jpcadas->cdCep))
   Else
      ::cCodigo   := jpcadas->cdCodigo
      ::cNome     := jpcadas->cdNome
      ::cEndereco := jpcadas->cdEndereco
      ::cCidade   := jpcadas->cdCidade
      ::cUf       := jpcadas->cdUf
      ::cCep      := jpcadas->cdCep
   Endif
   Return NIL   

Method Execute() Class CadastroCliente // monta tela
   ::Reload()
   Clear
   @ 1, 0 Say "Codigo....:" Get ::cCodigo Picture "@K 999999" When ::EditKeyEnabled Valid ::FindKey(@::cCodigo)
   @ 2, 0 Say "Nome......:" Get ::cNome   When ::EditFieldsEnabled
   @ 3, 0 Say "Cidade....:" Get ::cCidade When ::EditFieldsEnabled
   @ 4, 0 Say "UF........:" Get ::cUf     When ::EditFieldsEnabled
   @ 5, 0 Say "Cep.......:" Get ::cCep    When ::EditFieldsEnabled
   @ 10, 0 Get ::cWait
   @ Row(), Col()+1 Get ::cCmdSalva       When ::EditCmdEnabled  Send Reader := {|Get|::CmdSalvaClick(Get)}
   @ Row(), Col()+1 Get ::cCmdCancela     When ::EditCmdEnabled  Send Reader := {|Get|::CmdCancelaClick(Get)}
   @ Row()+1, 0 Say " "
   @ Row(), Col()+1 Get ::cCmdInclui      When ::NavegateCmdEnabled Send Reader := {|Get|::CmdIncluiClick(Get)}
   @ Row(), Col()+1 Get ::cCmdAltera      When ::NavegateCmdEnabled Send Reader := {|Get|::CmdAlteraClick(Get)}
   @ Row(), Col()+1 Get ::cCmdExclui      When ::NavegateCmdEnabled Send Reader := {|Get|::CmdExcluiClick(Get)}
   @ Row(), Col()+1 Get ::cCmdSeguinte    When ::NavegateCmdEnabled Send Reader := {|Get|::CmdSeguinteClick(Get)}
   @ Row(), Col()+1 Get ::cCmdAnterior    When ::NavegateCmdEnabled Send Reader := {|Get|::CmdAnteriorClick(Get)}
   @ Row(), Col()+1 Get ::cCmdPrimeiro    When ::NavegateCmdEnabled Send Reader := {|Get|::CmdPrimeiroClick(Get)}
   @ Row(), Col()+1 Get ::cCmdUltimo      When ::NavegateCmdEnabled Send Reader := {|Get|::CmdUltimoClick(Get)}
   @ Row(), Col()+1 Get ::cCmdLocaliza    When ::NavegateCmdEnabled Send Reader := {|Get|::CmdLocalizaClick(Get)}
   @ Row(), Col()+1 Get ::cCmdSair        When ::NavegateCmdEnabled Send Reader := {|Get|::CmdSairClick(Get)}
   Read 

*----------------------------------------------------------------
// Classe Generica
   
CREATE CLASS CadastroGenerico
   Data cCodigo             INIT " "
   Data cCampoGenerico      INIT " "
   Data cWait               INIT " "
   Data ccmdSalva           INIT "Salva"
   Data ccmdCancela         INIT "Cancela"
   Data ccmdInclui          INIT "Inclui"
   Data ccmdAltera          INIT "Altera"
   Data ccmdExclui          INIT "Exclui"
   Data ccmdAnterior        INIT "Anterior"
   Data ccmdSeguinte        INIT "Seguinte"
   Data ccmdPrimeiro        INIT "Primeiro"
   Data ccmdLocaliza        INIT "Localiza"
   Data ccmdUltimo          INIT "Ultimo"
   Data ccmdSair            INIT "Sair"
   Data EditKeyEnabled      INIT .f.
   Data EditFieldsEnabled   INIT .f.
   Data EditCmdEnabled      INIT .f.
   Data NavegateCmdEnabled  INIT .t.
   Method cmdSalvaClick(oGet)
   Method cmdCancelaClick(oGet)
   Method cmdIncluiClick(oGet)
   Method cmdAlteraClick(oGet)
   Method cmdPrimeiroClick(oGet)
   Method cmdAnteriorClick(oGet)
   Method cmdSeguinteClick(oGet)
   Method cmdUltimoClick(oGet)
   Method cmdExcluiClick(oGet)
   Method cmdLocalizaClick(oGet)
   Method cmdSairClick(oGet)
   Method SetKeyField(cValue)
   Method SetFields(lBlank)
   Method Reload()
   Method Execute()
   Method FindKey(cKey)
   ENDCLASS

Method cmdSalvaClick(oGet) Class CadastroGenerico
   If ::cCodigo == "*NOVO*"
      Goto Bottom
      ::cCodigo := StrZero(Val(jpcadas->cdCodigo)+1,6)
      Append Blank
      Replace jpcadas->cdCodigo With ::cCodigo
   Endif
   rLock()
   Replace generico->CampoGenerico With cCampoGenerico
   Skip 0
   Unlock   
   ::Reload()
   ::EditKeyEnabled     := .f.
   ::EditFieldsEnabled  := .f.
   ::EditCmdEnabled     := .f.
   ::NavegateCmdEnabled := .t.
   oGet:ExitState := GE_TOP
   Return NIL

Method cmdCancelaClick(oGet) Class CadastroGenerico
   ::Reload()
   ::EditKeyEnabled     := .f.
   ::EditFieldsEnabled  := .f.
   ::EditCmdEnabled     := .f.
   ::NavegateCmdEnabled := .t.
   oGet:ExitState := GE_TOP
   Return NIL

Method cmdIncluiClick(oGet) Class CadastroGenerico
   ::cCodigo            := "*NOVO*"
   ::EditFieldsEnabled  := .t.
   ::EditCmdEnabled     := .t.
   ::NavegateCmdEnabled := .f.
   oGet:ExitState := GE_TOP
   Return NIL

Method cmdAlteraClick(oGet) Class CadastroGenerico
   ::EditFieldsEnabled  := .t.
   ::EditCmdEnabled     := .t.
   ::NavegateCmdEnabled := .f.
   oGet:ExitState := GE_TOP
   Return NIL

Method cmdExcluiClick(oGet) Class CadastroGenerico
   Delete
   Skip 0
   Skip
   ::Reload()
   oGet:ExitState := GE_TOP
   Return NIL

Method cmdSeguinteClick(oGet) Class CadastroGenerico
   Skip 
   ::Reload()
   oGet:ExitState := GE_TOP
   Return NIL
   
Method cmdAnteriorClick(oGet) Class CadastroGenerico
   Skip -1
   ::Reload()
   oGet:ExitState := GE_TOP
   Return NIL
   
Method cmdPrimeiroClick(oGet) Class CadastroGenerico
   GoTo Top
   ::Reload()
   oGet:ExitState := GE_TOP
   Return NIL
   
Method cmdUltimoClick(oGet) Class CadastroGenerico
   Goto Bottom
   ::Reload()
   oGet:ExitState := GE_TOP
   Return NIL
   
Method cmdLocalizaClick(oGet) Class CadastroGenerico
   ::SetKeyField(.t.)
   ::SetFields(.t.)
   ::EditKeyEnabled     := .t.
   ::NavegateCmdEnabled := .f.
   ::EditCmdEnabled     := .t.
   oGet:ExitState := GE_TOP
   Return NIL

Method cmdSairClick(oGet) Class CadastroGenerico
   KeyBoard Chr(27)
   oGet:ExitState := GE_TOP
   Return NIL

Method SetKeyField(lEmpty) Class CadastroGenerico
   lEmpty := iif(lEmpty==NIL,.f.,lEmpty)
   If lEmpty
      ::cCodigo := Space(6)
   Else
      ::cCodigo := jpcadas->cdCodigo
   Endif
   Return NIL
   
Method SetFields(lEmpty) Class CadastroGenerico
   lEmpty := iif(lEmpty==NIL,.f.,lEmpty)
   If lEmpty
      ::cCodigo   := "*NOVO*"
      ::cNome     := Space(Len(jpcadas->cdNome))
   Else
      ::cCodigo   := jpcadas->cdCodigo
      ::cNome     := jpcadas->cdNome
   Endif
   Return NIL   

Method Reload() Class CadastroGenerico
   ::SetKeyField()
   ::SetFields()
   For nCont = 1 to Len(GetList)
      GetList[nCont]:Display()
   Next
   Return NIL

Method Execute() Class CadastroGenerico
   ::Reload()
   Clear
   @ 1, 0 Say "Codigo....:" Get ::cCodigo Picture "@K 99999" When ::EditKeyEnabled Valid ::FindKey(@::cCodigo)
   @ 2, 0 Say "Nome......:" Get ::cNome   When ::EditFieldsEnabled
   @ 10, 0 Get ::cWait
   @ Row(), Col()+1 Get ::cCmdSalva       When ::EditCmdEnabled  Send Reader := {|Get|::CmdSalvaClick(Get)}
   @ Row(), Col()+1 Get ::cCmdCancela     When ::EditCmdEnabled  Send Reader := {|Get|::CmdCancelaClick(Get)}
   @ Row()+1, 0 Say " "
   @ Row(), Col()+1 Get ::cCmdInclui      When ::NavegateCmdEnabled Send Reader := {|Get|::CmdIncluiClick(Get)}
   @ Row(), Col()+1 Get ::cCmdAltera      When ::NavegateCmdEnabled Send Reader := {|Get|::CmdAlteraClick(Get)}
   @ Row(), Col()+1 Get ::cCmdExclui      When ::NavegateCmdEnabled Send Reader := {|Get|::CmdExcluiClick(Get)}
   @ Row(), Col()+1 Get ::cCmdSeguinte    When ::NavegateCmdEnabled Send Reader := {|Get|::CmdSeguinteClick(Get)}
   @ Row(), Col()+1 Get ::cCmdAnterior    When ::NavegateCmdEnabled Send Reader := {|Get|::CmdAnteriorClick(Get)}
   @ Row(), Col()+1 Get ::cCmdPrimeiro    When ::NavegateCmdEnabled Send Reader := {|Get|::CmdPrimeiroClick(Get)}
   @ Row(), Col()+1 Get ::cCmdUltimo      When ::NavegateCmdEnabled Send Reader := {|Get|::CmdUltimoClick(Get)}
   @ Row(), Col()+1 Get ::cCmdLocaliza    When ::NavegateCmdEnabled Send Reader := {|Get|::CmdLocalizaClick(Get)}
   @ Row(), Col()+1 Get ::cCmdSair        When ::NavegateCmdEnabled Send Reader := {|Get|::CmdSairClick(Get)}
   Read 

Method FindKey(cCodigo) Class CadastroGenerico
   cCodigo := StrZero(Val(cCodigo),6)
   Seek cCodigo
   ::SetFields()
   Return .t.
*----------------------------------------------------------------


Classes e herança

Enviado: 08 Mar 2019 11:51
por NiltonGM
Oi Zeh, muito interessante, estou fazendo algo parecido, eu não sabia que podíamos usar os métodos e propriedades da CLASS pai dentro da CLASS filha sem usar o ::Super():<metodo ou propriedade da class pai>
Nesse caso, o Super() é só por motivo de compatibilidade?
Fiz alguns testes com herança, o Super() é para quando queremos usar um método ou propriedade do pai que tem o mesmo nome na class filha. Muito legal.

Classes e herança

Enviado: 08 Mar 2019 15:16
por JoséQuintas
NiltonGM escreveu:Nesse caso, o Super() é só por motivo de compatibilidade?
Não. Acabamos usando na prática.
Um exemplo simples, fazendo uso do SUPER.

Código: Selecionar todos

CLASS Cadastro
   METHOD Exclui()
   ENDCLASS

METHOD Exclui()
   IF MsgYesNo( "Confirma" )
     DELETE
   ENDIF
   RETURN NIL

Código: Selecionar todos

CLASS OutroCadastro INHERIT Cadastro
   METHOD Exclui()
   END CLASS

METHOD Exclui()
   IF EmUso()
      MsgStop( "Não pode excluir, está em uso" )
   ELSE
      ::SUPER:Exclui()
   ENDIF
   RETURN NIL

Classes e herança

Enviado: 20 Ago 2019 15:52
por lwinter
Gente muito legal os comentários de vocês.
Estou fazendo uma classe para trabalhar com classe e o código fonte final fica realmente muito mais fácil e intuitivo. Inclusive para dar manutenção.
:{