Página 5 de 7

Práticas que facilitam programar Clipper/Harbour

Enviado: 14 Jan 2016 09:14
por JoséQuintas
Quanto ao post anterior, de qualquer jeito, depende do programador incluir o recurso em suas práticas.

Outro exemplo: um array de coordenadas de mouse pra click, geralmente é um array multidimensional:

Código: Selecionar todos

FOR nCont = 1 TO Len( aAreaMouse )
   IF MRow() >= aAreaMouse[ nCont, 1 ] .AND. MCol() >= aAreaMouse[ nCont, 2 ] .AND. MCol()  <= aAreaMouse[ nCont, 3 ]
      nKey := aAreaMouse[ nCont, 4 ]
     EXIT
   ENDIF
NEXT

Código: Selecionar todos

FOR EACH oElement IN aAreaMouse
   IF MRow() >= oElement[ 1 ] .AND. MCol() >= oElement[ 2 ] .AND. MCol() <= oElement[ 3 ]
      nKey := oElement[ 4 ]
      EXIT
   ENDIF
NEXT
É até interessante, dá pra ter relação com um post anterior.
O "assunto" do bloco é aAreaMouse, todos os elementos do array.
E o "assunto" da rotina interna é cada um dos elementos desse array.
FOR EACH deixou isso bem claro no fonte.

Parece até que faz parte:
Acostumou a organizar o fonte e simplificar fonte, vai descobrindo técnicas/recursos que ajudam nisso.

A conclusão é que tem tudo a ver, é só começar que aos poucos tudo vém naturalmente.

Quanto a esse, pera aí que estou tentando verificar se nesse caso se aplica.

Práticas que facilitam programar Clipper/Harbour

Enviado: 14 Jan 2016 09:27
por JoséQuintas
Nem sempre dá pra aplicar o FOR EACH, depende muito do contexto.
E também não existe uma regra fixa de como usar.

Código: Selecionar todos

FOR nIdx := 1 to 25 STEP 2
  nLinha ++
  RestScreen(nIdx, 0, nIdx+1, 79, cTAbertura[nLinha])
  SysWait(.01)
NEXT
À primeira vista é uma rotina pra retornar textos na tela, onde aí é apenas uma página.
Sendo assim, o assunto principal seria cTAbertura.

Código: Selecionar todos

nIdx := 1
FOR EACH oElement IN cTAbertura
   RestScreen( nIdx, 0, nIdx + 1, 79, oElement )
   SysWait( .01 )
   nIdx += 2
   IF nIdx > 25
      // mudar página? ou EXIT?
     nIdx := 1
   ENDIF
NEXT
E internamente seria o controle de "quebra de página", ou algo parecido.
No meu ponto de vista, só é interessante alterar se a rotina completa tratar todo conteúdo de cTAbertura.
Vai de cada um.

Práticas que facilitam programar Clipper/Harbour

Enviado: 14 Jan 2016 11:42
por asimoes
Quintas,

Voltando ao assunto FOR EACH tem esses dois métodos muito úteis:

__enumIndex() equivalente a variável I:

FOR I:=1 TO Len(aVator)
NEXT
__enumIsLast() testa se i = Len(aVetor)

Código: Selecionar todos

cCampos:=""
FOR EACH aCampos IN aTheDBF
   cCampos+=IF(aCampos:__enumIndex() > 1,Space(1),"")+cNomeCampo + ' ' + cDecode + IF(!aCampos:__enumIsLast(),",",")")+ IF(!aCampos:__enumIndex(),HB_EOL(),"")
NEXT

Práticas que facilitam programar Clipper/Harbour

Enviado: 14 Jan 2016 12:10
por JoséQuintas
São interessantes.
Mas no caso desse uso, ficou complicado de entender o fonte, eu mesmo não entendi direito.
Me parece inclusive que tem erro.

Se entendi direito, deve ser algo parecido com isto:

Código: Selecionar todos

cCampos := ""
FOR EACH cNomeCampo IN aTheDBF
    cCampos += Space(1) + cNomeCampo + ' ' + cDecode + ","
NEXT
cCampos := Ltrim( Substr( cCampos, 1, Len( cCampos ) - 1 ) ) + ")" + hb_eol()
Lembre-se o fonte é pra nós, não para o compilador.
Se ficar difícil, pior pra nós.

Práticas que facilitam programar Clipper/Harbour

Enviado: 14 Jan 2016 12:24
por asimoes
No meu exemplo o destaque é para

oElemento:__enumIndex() e oElemento:__enumIsLast()

Código: Selecionar todos

 aVetor:={"A", "B", "C"}
 cValor:=""
 FOR EACH oElemento IN aVetor
    cValor += oElemento + IF(!oElemento:__enumIsLast(), ",", "")
 NEXT
 cValor:=""
 FOR EACH oElemento IN aVetor
    cValor += StrZero(oElemento:__enumIndex,2)+" "+oElemento + IF(!oElemento:__enumIsLast(), ", ", "")
 NEXT
1º Resulta: A,B,C
2º Resulta: 01 A, 02 B, 03 C

Práticas que facilitam programar Clipper/Harbour

Enviado: 14 Jan 2016 12:36
por JoséQuintas
ok, era apenas pra mostrar que existe a opção de obter mais informações da variável do FOR EACH.

Em todo caso, só pra lembrar:

Nosso maior tempo é gasto em alterações, então o fonte tem que ser voltado pra ganhar tempo em alteração.

Olhou, entendeu, alterou, fim.
Olhou, não entendeu, já se começa a perder tempo a partir daí.

Só compensa complicar em casos extremos, aonde milésimos de segundo fizerem diferença.
Ainda não peguei um caso assim.

Práticas que facilitam programar Clipper/Harbour

Enviado: 14 Jan 2016 12:48
por asimoes
A questão é se vai usar FOR EACH conheça bem os recursos que pode utilizar.

Práticas que facilitam programar Clipper/Harbour

Enviado: 14 Jan 2016 12:55
por asimoes
Um exemplo que está no changelog.txt

Código: Selecionar todos

       proc main()
         local v, h:={"a"=>1.000,"b"=>2.000,"c"=>3.000}
         heval( h, { |k,v,i| qout( k, v, i ) } ); ?
         for each v in h
            ? v, "=>", v:__enumKey(), v:__enumValue(), v:__enumIndex(), ;
                       valtype(v:__enumBase())
            v += 0.123
         next
         ? ;heval( h, { |k,v,i| qout( k, v, i ) } )
         return

Práticas que facilitam programar Clipper/Harbour

Enviado: 14 Jan 2016 13:00
por JoséQuintas
Acho essa invenção péssima, variável hash.
E tem gente que ainda abusa.

Práticas que facilitam programar Clipper/Harbour

Enviado: 17 Jan 2016 13:48
por fladimir
Quintas,

Dentro das práticas q facilitam programar Clipper/Harbour vc mencionou q acha péssima etc...

Gostaria de saber pq?

Eu uso para tratar arquivos INI

Exemplo:

Código: Selecionar todos

...
	hINI := HB_ReadIni( cArqZ ) // ATENCAO É CASE SENSITIVE.

	aGet       := Inicia_Var(aGet, "MAPARES")

	aGet[D_DATAMOVZ] := CTOD( hINI["ECF"]["DATAMOVIMENTO"] ) //= 09/12/13
	aGet[D_NUMSERIE]  := hINI["ECF"]["NUMSERIE"]        //= 00000000000000000001

	*-- Verifica se a Chave existe no Hash
	if HHasKey( hINI["TOTALIZADORES"], "GRANDETOTAL" )
		aGet[D_GT_FINAL]   := StrToVal( hINI["TOTALIZADORES"]["GRANDETOTAL"]   ) 
	endif		

	aGet[D_DESCONTOS]  := StrToVal( hINI["TOTALIZADORES"]["TOTALDESCONTOS"]     ) 

...

Práticas que facilitam programar Clipper/Harbour

Enviado: 17 Jan 2016 15:54
por JoséQuintas
Desse jeito você não consegue validar o fonte.
Acontece isso com variável PRIVATE, PUBLIC, variável HASH, até mesmo classes e métodos.

No caso de hash, um .CH pode ajudar.
Acho até que foi feito só pra compatibilidade com xHarbour.

Quanto ao INI, não deixa de ser uma opção.
Mas prefiro XML mesmo, mais prático e com mais recursos.

No caso de classes e métodos... vale a pena o risco.

Práticas que facilitam programar Clipper/Harbour

Enviado: 18 Jan 2016 11:22
por JoséQuintas
Uia, a compilação -w3 -es2 acabou de me salvar.
d:\CDROM\FONTES\HAROLDO>hbmk2 hl.hbp -comp=msvc
hbmk2: Processing environment options: -comp=msvc
hbmk2: Building sub-project (level 2): libjose.hbp
hbmk2: Processing environment options: -comp=msvc
hbmk2: Target up to date: libjose.lib
hbmk2: Compiling Harbour sources...
Harbour 3.4.0dev (0a127e0) (2016-01-15 01:54)
Copyright (c) 1999-2016, https://github.com/vszakats/harbour-core/
Compiling 'VHLAL01.prg'...
VHLAL01.prg(646) Warning W0032 Variable 'CPALAVRA' is assigned but not used in function 'MYSQLENDERECOLIKE(642)'
Apaguei uma linha a mais do fonte sem querer, aonde usava cPalavra, por isso o erro.

Se não fosse a compilação -w3 -es2, ia demorar muuuito pra descobrir isso.
Como ela avisou, o fonte anterior estava na mão.

Na correria do dia a gente não percebe esses detalhes.

A compilação -w3 -es2 não é apenas uma checagemzinha de escrever o fonte direito.
E também não é só na hora de criar um fonte novo.
É uma ajuda SEMPRE, pra qualquer alteração.
Acho que quando mencionei sobre a compilação com -w3 -es2 não chamei a atenção pra isso.

Imagine nesse caso acima, é um módulo com umas 15 opções de pesquisa diferentes, e a linha que apaguei era usada somente em uma determinada condição.
Eu iria demorar meses pra descobrir o que aconteceu.
Na compilação -w3 -es2 foi instantâneo, já mostrou no instante em que apaguei a linha.

É programar sem erros, mesmo errando.... rs

Práticas que facilitam programar Clipper/Harbour

Enviado: 18 Jan 2016 11:29
por JoséQuintas
O programa git também ajuda a conferir as alterações.

Acabei de alterar na parte de cima de um jeito, e alterei a parte de baixo de outro.
alteracao.png
No fonte as coisas ficam longe, no git fica pertinho.
Dá pra conferir exatamente o que foi alterado.
Se o erro anterior passasse na compilação, talvez eu pegasse por aqui, porque ia mostrar que apaguei aquela linha.

Práticas que facilitam programar Clipper/Harbour

Enviado: 09 Jul 2016 11:11
por JoséQuintas
Reavaliando o post do ASimões:

Código: Selecionar todos

cCampos:=""
FOR EACH aCampos IN aTheDBF
    cCampos+=IF(aCampos:__enumIndex() > 1,Space(1),"")+cNomeCampo + ' ' + cDecode + IF(!aCampos:__enumIsLast(),",",")")+ IF(! aCampos:__enumIndex(),HB_EOL(),"")
NEXT
Sinceramente, não entendi o que ele faz, vamos por bloco.

Código: Selecionar todos

cCampos := ""
FOR EACH aCampos IN aTheDBF
    cCampos += ;
   IF(aCampos:__enumIndex() > 1, Space(1), "" ) + ;  // ok, só no primeiro não tem espaço, poderia ser AllTrim() fora do loop
   cNomeCampo + ;                                                 // de onde vém isso?
   ' ' + ;
   cDecode + ;                                                        // de onde vém isso?
   IF( ! aCampos:__enumIsLast(), ",", ")" ) + ;           // ok, no último é ")", nos demais ",", poderia trocar no final fora do loop
   IF( ! aCampos:__enumIndex(), HB_EOL(), "" )       // não sei pra que serve isto. Se __enumindex() é número, tá esquisito.
NEXT
Provavelmente era o começo da alteração, e o fonte ficou parcial.

Práticas que facilitam programar Clipper/Harbour

Enviado: 28 Set 2016 13:43
por JoséQuintas
Uma pequena melhoria que uso nos GETs.
Uso um bloco alterado na GETSYS - a parte com by JPA

Código: Selecionar todos

   DO WHILE ! nPos == 0
      aVarGet := Array( Len( GetList ) )  // by JPA to otimize screen update
      FOR EACH oElement IN GetList        // by JPA to otimize screen update
         aVarGet[ oElement:__EnumIndex ] := oElement:VarGet()
      NEXT

      // GET NEXT GET from list and post it as the active GET
      PostActiveGet( oGet := GetList[ nPos ] )

      // Read the GET
      IF ( VALTYPE( oGet:reader ) == "B" )
         EVAL( oGet:reader, oGet )    // Use custom reader block
      ELSE
         GetReader( oGet, lIsMouse )            // Use standard reader
      ENDIF

      FOR EACH oElement IN GetList // by JPA to otimize screen update
         IF aVarGet[ oElement:__EnumIndex ] != oElement:VarGet()
            oElement:Display()
         ENDIF
      NEXT
      // Move to NEXT GET based on EXIT condition
      nPos := Settle( GetList, nPos )

   ENDDO
Nada demais, só atualiza a tela caso o conteúdo do GET tenha sido alterado.

Muito útil quando a digitação altera o conteúdo de outros GETs, porque na GETSYS normal isso só acontece se passar pelo GET.

Código: Selecionar todos

#include "hbclass.ch"
PROCEDURE Main

SetMode( 35, 100 )
SetColor( "W/B,N/W,,,W/B" )
CLS
Nota := NotaClass():New()
@ 1, 0 SAY "Valor da Nota:" GET Nota:Valor VALID Nota:CalculaImpostos()
@ 2, 0 SAY "Base ICMS....:" GET Nota:IcmBase WHEN .F.
@ 3, 0 SAY "Base Reducao.:" GET Nota:IcmReducao VALID Nota:CalculaImpostos()
@ 4, 0 SAY "Alíquota.....:" GET Nota:IcmAliquota VALID Nota:CalculaImpostos()
@ 5, 0 SAY "Valor ICMS...:" GET Nota:IcmValor WHEN .F.
@ 6, 0 SAY "Base ST......:" GET Nota:StBase WHEN .F.
@ 7, 0 SAY "IVA..........:" GET Nota:StIVA VALID Nota:CalculaImpostos()
@ 8, 0 SAY "Aliq.ST......:" GET Nota:StAliquota VALID Nota:CalculaImpostos()
@ 9, 0 SAY "Valor ST.....:" GET Nota:StValor WHEN .F.
READ

CREATE CLASS NotaClass
   VAR Valor       INIT 0
   VAR IcmBase     INIT 0
   VAR IcmReducao  INIT 0
   VAR IcmAliquota INIT 0
   VAR IcmValor    INIT 0
   VAR StBase      INIT 0
   VAR StIVA       INIT 0
   VAR StAliquota  INIT 0
   VAR StValor     INIT 0
   METHOD CalculaImpostos()
   END CLASS

METHOD CalculaImpostos()

   ::IcmBase := ::Valor - ( Int( ::Valor * ::IcmReducao ) / 100 )
   ::IcmValor := Int( ::IcmBase * ::IcmAliquota ) / 100
   ::StBase := ::IcmBase + ( Int( ::IcmBase * ::StIVA / 100 ) )
   ::StValor := Max( 0, Int( ::StBase * ::StAliquota ) / 100 - ::IcmValor )
   SetPos( 11, 0 )
   ? "Icmbase:", ::IcmBase, "STBase", ::StBase
   RETURN .T.
Sem alterar a getsys, valores errados na tela, ou necessidade de fonte adicional:

Código: Selecionar todos

Valor da Nota:        100
Base ICMS....:        100.00
Base Reducao.:         20
Alφquota.....:         10
Valor ICMS...:          8.00
Base ST......:         80.00
IVA..........:         50
Aliq.ST......:         10
Valor ST.....:          4.00


Icmbase:         80.00 STBase        120.00
Até lembrei das estorinhas de criança, que tinham o "moral da estória".
Acho que isso era algo do tipo: "use a cabeça e pense".

Qual o moral da estória aqui:
Problema resolvido de vez, sem complicar os fontes de trabalho.
Se é pra complicar, que seja pra simplificar.