Página 1 de 1

Super:Super:AlgumaCoisa()

Enviado: 16 Set 2013 18:03
por JoséQuintas
Tem isso no Harbour?
Tem como escolher uma das classes herdadas superiores através de super:super ou super: ?
(escolher entre roitna da classe herdada, ou rotina que a classe herdada havia herdado de outra)

Obs. Acho que cheguei no nível 5 de herança, e precisava algo da classe do nível 4.

Super:Super:AlgumaCoisa()

Enviado: 16 Set 2013 18:24
por JoséQuintas
Não, não é pra complicar, é pra facilitar.
Por enquanto meu cadastro de mídia está assim:

Código: Selecionar todos

PROCEDURE PAUXMIDIA
   LOCAL oFrm := AUXMIDIAClass():New()
   
   IF .NOT. AbreArquivos( { "jptabel" } )
      RETURN
   ENDIF
   SELECT jptabel
   SET FILTER TO jptabel->axTabela == "MIDIA."
   oFrm:Execute()
   CLOSE DATABASES
   RETURN 

CREATE CLASS AUXMIDIAClass INHERIT AUXILIARClass
   DATA cTabelaAuxiliar INIT "MIDIA."
   END CLASS
E alguns outros cadastros genéricos estão parecidos.
Mas este, assim como outros cadastros já receberam, vai receber um método Exclui() próprio, pra verificar se o código está sendo usado antes de excluir.
Pelo menos na parte final é chamar o Super;Exclui() que pega o Exclui() da classe principal, que só pede confirmação e exclui o registro atual.

Mas se precisar de um método da classe intermediária, como fazer?

Super:Super:AlgumaCoisa()

Enviado: 16 Set 2013 18:27
por JoséQuintas
A classe que foi herdada pelo anterior é esta:

Código: Selecionar todos

CREATE CLASS AUXILIARClass INHERIT FrmCadastroClass
   DATA   cTabelaAuxiliar INIT "NAOTEM"
   METHOD Especifico( lExiste )
   METHOD TelaDados( lDigita )
   METHOD Valida( cCodigo, lShow )
   METHOD GridSelection()
   END CLASS
   
METHOD GridSelection() CLASS AUXILIARClass
   LOCAL oTBrowse, nSelect := Select(), cOrdSetFocus
   
   oTBrowse := { ;
      { "NOME",   "jptabel->axDescri" }, ;
      { "CODIGO", "jptabel->axCodigo" } }
   SELECT jptabel
   SELECT jptabel
   cOrdSetFocus := OrdSetFocus( "descricao" )
   FazBrowse( oTBrowse,, ::cTabelaAuxiliar )
   IF LastKey() != K_ESC .AND. .NOT. Eof()
      KEYBOARD jptabel->axCodigo + Chr( K_ENTER )
   ENDIF
   OrdSetFocus( cOrdSetFocus )
   SELECT ( nSelect )
   RETURN NIL

METHOD Especifico( lExiste ) CLASS AUXILIARClass
   LOCAL GetList := {}
   LOCAL maxCodigo := jptabel->axCodigo

   IF ::cOpc == "I"
      maxCodigo := "*NOVO*"
   ENDIF   
   @ Row()+1, 20 GET maxCodigo PICTURE "@K 999999" VALID iif(maxCodigo == "*NOVO*",.t.,vZeros(@maxCodigo) .AND. Val(maxCodigo) > 0 )
   Mensagem( "Digite codigo, <F9> pesquisa, <ESC> volta" )
   READ
   Mensagem()
   IF LastKey() == K_ESC .OR. ( Val(maxCodigo) == 0 .AND. maxCodigo != "*NOVO*" )
      GOTO ::nUltRec
      RETURN .f.
   ENDIF
   SEEK ::cTabelaAuxiliar + maxCodigo
   IF .NOT. ::EspecificoExiste( lExiste, Eof() )
      RETURN .f.
   ENDIF
   ::cChave := { maxCodigo }
   RETURN .t.
   
METHOD TelaDados( lDigita ) CLASS AUXILIARClass
   LOCAL GetList := {}
   LOCAL maxCodigo := jptabel->axCodigo
   LOCAL maxDescri := jptabel->axDescri
   LOCAL maxInfInc := jptabel->axInfInc
   LOCAL maxInfAlt := jptabel->axInfAlt
   
   lDigita   := iif( lDigita == NIL, .f., lDigita )
   IF lDigita
      maxCodigo := ::cChave[1]
      ::nNumTab := 1
   ENDIF
   DO WHILE .t.
      ::ShowTabs()
      DO CASE
      CASE ::nNumTab == 1
         @ Row()+1, 1  SAY "Codigo...........:" GET maxCodigo  WHEN .f.
         @ Row()+2, 1  SAY "Descricao........:" GET maxDescri  PICTURE "@!" VALID .NOT. Empty( maxDescri )
         @ Row()+2, 1  SAY "Inf.Inclusao.....:" GET maxInfInc  WHEN .f.
         @ Row()+1, 1  SAY "Inf.Alteracao....:" GET maxInfAlt  WHEN .f.
      ENDCASE
      IF .NOT. lDigita
         CLEAR GETS
         EXIT
      ENDIF
      Mensagem( "Digite campos, <F9> Pesquisa, <ESC> Sai" )
      READ
      Mensagem()
      ::nNumTab += 1
      IF LastKey() == 27
         EXIT
      ENDIF
      IF ::nNumTab > Len(::acTabName)
         EXIT
      ENDIF
   ENDDO
   IF .NOT. lDigita
      RETURN NIL
   ENDIF
   ::nNumTab := 1
   IF LastKey() == K_ESC
      RETURN NIL
   ENDIF
   IF ::cOpc == "I"
      maxCodigo := ::cChave[1]
      IF maxCodigo == "*NOVO*"
         GOTO BOTTOM
         maxCodigo := StrZero( Val( jptabel->axCodigo ) + 1, 6 )
      ENDIF   
      Inclui(.t.)
      REPLACE jptabel->axTabela WITH ::cTabelaAuxiliar, jptabel->axCodigo WITH  maxCodigo, jptabel->axInfInc WITH LogInfo()
      SKIP 0
      UNLOCK
   ENDIF
   Bloqueia(.t.)
   REPLACE jptabel->axDescri WITH maxDescri
   IF ::cOpc == "A"
      REPLACE jptabel->axInfAlt WITH LogInfo()
   ENDIF   
   SKIP 0
   UNLOCK
   RETURN NIL
   
METHOD Valida( cCodigo, lShow ) CLASS AUXILIARClass
   LOCAL lOk := .t., nRow := Row()
   MEMVAR m_Prog
   lShow := iif( lShow == NIL, .t., lShow )
   IF lShow
      @ nRow, 32 SAY EmptyValue( jptabel->axDescri )   
   ENDIF
   cCodigo := StrZero( Val( cCodigo ), 6 )
   IF .NOT. Encontra( ::cTabelaAuxiliar + cCodigo, "jptabel", "numlan" ) 
      MsgWarning( "Codigo nao cadastrado!" )
      lOk := .f.
   ENDIF
   IF lShow
      @ nRow, 32 SAY jptabel->axDescri
   ENDIF
   RETURN lOk

Super:Super:AlgumaCoisa()

Enviado: 16 Set 2013 18:41
por JoséQuintas
E essa herda de outra que faz a navegação do cadastro, que herda de outra que faz a parte visual.
Só está separado em classes "por assunto".
Uma classe cuida do visual, outra cuida da navegação do cadastro.
Sobra para o cadastro o que é específico, como liberar acesso conforme senha, validações em geral, telas específicas, etc.

Nesse fonte dá pra eliminar ::nNumTab, já que esse cadastro não precisa de TABS pra multijanelas.
Aliás... esse é o lado ruim de classes: a compilação /w3 /es2 não consegue analisar partes inúteis.

Super:Super:AlgumaCoisa()

Enviado: 16 Set 2013 18:52
por JoséQuintas
Uma outra com algo mais:

Código: Selecionar todos

PROCEDURE PAUXPRODEP
   LOCAL oFrm := AUXPRODEPClass():New()
   
   IF .NOT. AbreArquivos( { "jpconfi", "jptabel", "jpitem", "jpnumero", "jpsenha", "jptabel", "jpreguso" } )
      RETURN 
   ENDIF   
   SELECT jptabel
   SET FILTER TO jptabel->axTabela == "PRODEP"
   oFrm:Execute()
   CLOSE DATABASES
   RETURN 

CREATE CLASS AUXPRODEPClass INHERIT FrmCadastroClass
   DATA cTabelaAuxiliar INIT "PRODEP"
   METHOD Intervalo( nLini, nColi, nOpc, mieprodep )
   END CLASS

METHOD Intervalo( nLini, nColi, nOpc, mieprodep )  CLASS AUXPRODEPClass
   LOCAL acTxtOpc := { "Todos", "Especifico" }
   LOCAL GetList := {}
   
   WAchoice( nLini, nColi, acTxtOpc, @nOpc, "Depto de produto" )
   IF nOpc == 2
      wOpen( nLini, nColi + 10, nLini + 3,  nColi + 50, "Depto de produto" )
      @ nLini + 2, nColi + 12 GET mieProDep PICTURE "@K 999999" VALID ::Valida( @mieProDep )
      Mensagem( "Digite Departamento de Produto, <F9> Pesquisa, <ESC> Sai" )
      READ
      wClose()
   ENDIF
   RETURN nOpc

Super:Super:AlgumaCoisa()

Enviado: 02 Out 2013 17:40
por JoséQuintas
Só pra classe intermediária é que não encontrei, mas não sei se é seguro fazer isso.
Pra usar da classe principal é normal, super: funciona.

Classe principal

Código: Selecionar todos

CREATE CLASS CadastroClass
   METHOD Exclui()
   END CLASS

METHOD Exclui CLASS CadastroClass
   IF MsgYesNo( "Confirma exclusão" )
       Bloqueia(.t.)
       DELETE
       SKIP 0
      UNLOCK
   ENDIF
   RETURN NIL
Classe que recebe herança

Código: Selecionar todos

CREATE CLASSS ProdutoClass INHERIT CadastroClass
   METHOD Exclui()
   END CLASS

METHOD Exclui() CLASS ProdutoClass
   IF produto->Qtde != 0
      MsgExclamation( "Não pode excluir produto com saldo" )
      RETURN NIL
   ENDIF
   Super:Exclui()
   RETURN NIL
Classe() é a classe.
Classe():New() é o método New() da classe.
Pra passar um parâmetro pro método New(), teria que estar nele. New( 10 )
Deve ser uma das diferenças entre Harbour x xHarbour.
Não sei se poderia ser considerado erro.

Super:Super:AlgumaCoisa()

Enviado: 02 Out 2013 18:09
por JoséQuintas
Fiz um teste aqui:

O New() é a criação da classe, e o Init() a inicialização, não sei se CONSTRUCTOR afeta alguma coisa.
Mas o Init() não recebe parâmetro. Neste exemplo, ::nNumero retorna NIL, porque INIT() foi executado mas não tem parâmetro.
A não ser que alterem, somente o New() que é garantido pra iniciar com valores.

Código: Selecionar todos

#include "hbclass.ch"

PROCEDURE Main
   oClasse := TesteClass( 10 ):New()
   ? oClasse:nNumero
   RETURN
   
CREATE CLASS TesteClass
   VAR nNumero INIT 0
   METHOD Init( nNumero )
   END CLASS

METHOD Init( nNumero ) CLASS TesteClass
   ::nNumero := nNumero
   RETURN NIL
Detalhe curioso: se não iniciar a classe com New(), o método Init() não é executado.

Super:Super:AlgumaCoisa()

Enviado: 03 Nov 2013 05:54
por JoséQuintas
Sobre classes intermediárias.
Encontrei a resposta nos fontes da gtwvg.

Por exemplo, separei a parte de callback da wvgwindow, e chamei de wvgCallback.
E peguei por herança na wvgwindow.

Mas o Destroy() da wvgWindow eliminava as rotinas de Callback.
Pra não duplicar código, coloquei no Destroy() da wvgWindow uma chamada pra ::wvgcallback:Destroy()

Isso permitiu chamar o método específico da classe wvgCallback.

Obs.
Por enquanto só estou tentando entender a wvg. Não tá fácil entender.
Essa separação ajuda por dividir o fonte "por assunto".
E a wvgWindow é a base pra tudo, então o fonte é extenso.