Depois de muitos problemas com campo memo, contribuo com vocês a solução que usamos
em nossos sistemas clipper para o campo memo. A solução grava, lê e exclui somente o registro que precisa da informação de texto.
Código: Selecionar todos
/*
Solução para substituir campo memo de dbf.
O campo memo em dbf ocupa espaço e pode corromper o dbf.
Exemplo de uso:
Criar um dbf com nome arqobs (nome opcional)
Com a seguinte estrutura:
DBCREATE("ARQOBS.DBF", {
{ "CHAVE", "C", 5, 0 },;
{ "NUM_LINHA", "C", 4, 0 },;
{ "LINHA_MEMO", "C", 80, 0 },;
})
A chave de indice:
INDEX ON Chave+Num_Linha TAG "C0001" TO ARQOBS
Para gravar o memo:
A área DBFORI: Deve estar indexada, o conteúdo da chave de indice de DBFORI será gravado
no campo chave de ARQOBS usando INDEXKEY(), ver documentação da função F_GrMemo()
cObsMemo:=MEMOEDIT(cObsMemo,3,1,22,78, lEdita,"UFUNC", 80)
F_GrMemo(cObsMemo, 80, "DBFORI", "ARQOBS")
Para ler o memo:
cObsMemo:=F_LeMemo("DBFORI", "ARQOBS")
A área de DBFORI deve estar indexada com o mesmo INDEXKEY() de ARQOBS.
Para excluir:
F_DelMemo("DBFORI", "ARQOBS")
A área de DBFORI deve estar indexada com o mesmo INDEXKEY() de ARQOBS.
*/
#include "common.ch"
******************************************************************************
FUNCTION F_LeMemo(cArqMestre, cArqMemo, cEspecial)
******************************************************************************
* Autor(es) : Carlos Eduardo Taylor *
* Data : Agosto/1999 *
*----------------------------------------------------------------------------*
* Ojetivo : Le as linhas de memo do arq. MEMO para uma variavel memo *
* Observacao : O arquivo Mestre deve estar posicionado na chave correta *
* O arquivo Memo deve ter os campos: *
* - CHAVE (carac.,tam >= tamanho da concatenacao completa *
* da chave do cArqMestre) *
* - NUM_LINHA (carac.,tam = qualquer) *
* - LINHA_MEMO (carac.,tam >= P_TAM) *
* O arquivo Memo deve estar indexado por CHAVE + NUM_LINHA *
* Sintaxe : F_LeMemo(cArqMestre, cArqMemo, [cEspecial]) *
* Parametros : <cArqMestre> - nome do arquivo mestre *
* <cArqMemo> - nome do arquivo onde ser„o lidas as linhas *
* memo *
* [<cEspecial>]- utilizado para qualquer condi‡„o especial *
* a ser inserida na fun‡„o (DEFAULT "") *
* Retorno : cMemo - variavel do memoedit *
* Fun. chamadas : *
* Arquivo fonte : ArqMemo.prg *
* Arq. de dados : arquivo mestre e arquivo memo *
* Veja tamb‚m : *
******************************************************************************
LOCAL cMemo,cChave,bGrava,bCondicao,aMemo:={},i
LOCAL cAlias := ALIAS()
DEFAULT cEspecial TO ""
cMemo := ""
SELECT (cArqMestre)
bGrava := { || cMemo += TRIM((cArqMemo)->Linha_Memo) + CHR(13)+CHR(10) }
IF EMPTY(cEspecial)
cChave := &((cArqMestre)->(INDEXKEY()))
bCondicao:= { || TRIM((cArqMemo)->Chave) == cChave .AND. (cArqMemo)->(!EOF()) }
ELSEIF LEFT(cEspecial,5) == 'CHAVE' // Especifica String Chave
cChave := RIGHT(cEspecial,LEN(cEspecial) - 5)
bCondicao:= { || TRIM((cArqMemo)->Chave) == cChave .AND. (cArqMemo)->(!EOF()) }
ENDIF
SELECT (cArqMemo)
OrdSetFocus(1)
(cArqMemo)->(DBSEEK(cChave))
(cArqMemo)->(DBEVAL(bGrava,,bCondicao,,,.T.))
IF !EMPTY(cAlias)
SELECT (cAlias)
ENDIF
RETURN cMemo
******************************************************************************
FUNCTION F_GrMemo(cMemo, nTam, cArqMestre, cArqMemo, cEspecial)
******************************************************************************
* Autor(es) : Alexandre Simäes *
* Data : Agosto/1999 *
*----------------------------------------------------------------------------*
* Ojetivo : Grava as linhas de memo no cArqMemo a partir de uma *
* variavel memo/car. *
* Observacao : O arquivo Mestre deve estar posicionado na chave correta *
* O arquivo Memo deve ter os campos: *
* - CHAVE (carac.,tam >= tamanho da concatenacao completa *
* da chave do cArqMestre) *
* - NUM_LINHA (carac.,tam = qualquer) *
* - LINHA_MEMO (carac.,tam >= P_TAM) *
* O arquivo Memo deve estar indexado por CHAVE + NUM_LINHA *
* Sintaxe : GrMemo(cMemo, nTam, cArqMestre, cArqMemo, [cEspecial],; *
* Parametros : <cMemo> - variavel do memoedit a ser gravada *
* <nTam> - tamanho da linha *
* <cArqMestre> - nome do arquivo mestre *
* <cArqMemo> - nome do arquivo onde ser„o gravadas as *
* linhas de memo *
* [<cEspecial>]- utilizado para qualquer condi‡„o especial *
* a ser inserida na fun‡„o (DEFAULT "") *
* Retorno : NIL *
* Fun. chamadas : *
* Arquivo fonte : ArqMemo.prg *
* Arq. de dados : arquivo mestre e arquivo memo *
* Veja tamb‚m : *
******************************************************************************
LOCAL nTotLinha,i,j,cChave,nLen,dDtAux,CContinue:=0
LOCAL aCols:={},aAnda:={},lValido:=.T.
LOCAL cNumLinha,cLinhaMemo
LOCAL cAlias := ALIAS()
DEFAULT cEspecial TO ""
SELECT (cArqMestre)
IF EMPTY(cEspecial)
cChave := &((cArqMestre)->(INDEXKEY()))
ELSEIF LEFT(cEspecial,5) == 'CHAVE'
cChave := RIGHT(cEspecial,LEN(cEspecial) - 5)
ENDIF
IF !EMPTY(cAlias)
SELECT (cAlias)
ENDIF
nLen := LEN((cArqMemo)->NUM_LINHA)
nTotLinha:= MLCOUNT(cMemo,nTam)
i := 0
IF EMPTY(cEspecial) .OR. LEFT(cEspecial,5) == 'CHAVE'
* Grava primeiro sobre as linhas da mesma chave se houverem:
IF (cArqMemo)->(DBSEEK(cChave))
WHILE TRIM((cArqMemo)->CHAVE) == cChave .AND. ;
(cArqMemo)->(!EOF()) .AND. i < nTotLinha
i ++
(cArqMemo)->(DbRLock())
REPLACE (cArqMemo)->LINHA_MEMO WITH MEMOLINE(cMemo,nTam,i)
(cArqMemo)->(DBCOMMIT())
(cArqMemo)->(DBUNLOCK())
(cArqMemo)->(DBSKIP())
ENDDO
ENDIF
* Apaga as linhas restantes da mesma chave se houverem: (novo memo menor que o anterior)
WHILE TRIM((cArqMemo)->CHAVE) == cChave .AND. (cArqMemo)->(!EOF())
(cArqMemo)->(DbRLock())
(cArqMemo)->(DBDELETE())
(cArqMemo)->(DBCOMMIT())
(cArqMemo)->(DBUNLOCK())
(cArqMemo)->(DBSKIP())
ENDDO
* Acrescenta linhas novas se o novo memo for maior que o anterior:
FOR j := i+1 TO nTotLinha STEP 1
(cArqMemo)->(DbAppend())
REPLACE (cArqMemo)->CHAVE WITH cChave ,;
(cArqMemo)->NUM_LINHA WITH STRZERO(j,nLen) ,;
(cArqMemo)->LINHA_MEMO WITH MEMOLINE(cMemo,nTam,j)
(cArqMemo)->(DBCOMMIT())
(cArqMemo)->(DBUNLOCK())
NEXT
ENDIF
RETURN lValido
******************************************************************************
FUNCTION F_DelMemo(cArqMestre, cArqMemo, cEspecial)
******************************************************************************
* Autor(es) : Carlos Eduardo Taylor *
* Data : Agosto/1999 *
*----------------------------------------------------------------------------*
* Ojetivo : Apaga as linhas de memo no cArqMemo a partir de uma *
* chave. *
* Observacao : O arquivo Mestre deve estar posicionado na chave correta *
* O arquivo Memo deve ter os campos: *
* - CHAVE (carac.,tam >= tamanho da concatenacao completa *
* da chave do cArqMestre) *
* - NUM_LINHA (carac.,tam = qualquer) *
* - LINHA_MEMO (carac.,tam >= P_TAM) *
* O arquivo Memo deve estar indexado por CHAVE + NUM_LINHA *
* Sintaxe : F_DelMemo(cArqMestre, cArqMemo, [cEspecial]) *
* Parametros : <cArqMestre> - nome do arquivo mestre *
* <cArqMemo> - nome do arquivo onde ser„o apagadas as *
* linhas de memo *
* [<cEspecial>]- utilizado para qualquer condi‡„o especial *
* a ser inserida na fun‡„o (DEFAULT "") *
* Retorno : NIL *
* Fun. chamadas : *
* Arquivo fonte : ArqMemo.prg *
* Arq. de dados : arquivo mestre e arquivo memo *
* Veja tamb‚m : *
******************************************************************************
LOCAL cChave,cTabela,CContinue:=0
LOCAL cAlias := ALIAS()
DEFAULT cEspecial TO ""
SELECT (cArqMestre)
IF EMPTY(cEspecial)
cChave := &((cArqMestre)->(INDEXKEY()))
ELSEIF LEFT(cEspecial,5) == 'CHAVE'
cChave := RIGHT(cEspecial,LEN(cEspecial) - 5)
ENDIF
IF !EMPTY(cAlias)
SELECT (cAlias)
ENDIF
* Apaga as linhas da mesma chave se houverem:
IF (cArqMemo)->(DBSEEK(cChave))
IF EMPTY(cEspecial)
WHILE TRIM((cArqMemo)->CHAVE) == cChave .AND. (cArqMemo)->(!EOF())
(cArqMemo)->(DbRLock())
(cArqMemo)->(DBDELETE())
(cArqMemo)->(DBCOMMIT())
(cArqMemo)->(DBUNLOCK())
(cArqMemo)->(DBSKIP())
ENDDO
ENDIF
ENDIF
RETURN NIL