Files
comun/docs/creare-editare-rapoarte-frx.md
2026-09-24 23:07:59 +03:00

5.6 KiB

Rapoarte VFP (.frx/.frt): citire, creare, verificare

Un .frx este un DBF cu 75 de campuri fixe (identice la toate rapoartele) + memo-ul .frt. goExport.export2frx(cursor, "nume", ...) il lanseaza; getRepPath (oexport.prg) cauta nume.frx in SET PATH (Rapoarte\) sau in USERREPORTS\<schema>\USR_nume.frx. Cursorul selectat inainte de Report Form este sursa expresiilor din raport.

Campuri cheie

  • OBJTYPE: 1=raport (OBJCODE=53), 9=banda, 5=eticheta, 8=expresie/camp, 6=linie, 7=dreptunghi (OBJCODE=4), 18=variabila de raport, 25=dataenvironment.
  • OBJCODE pe OBJTYPE=9: 0=Title, 1=Page Header, 2=Column Header, 3=Group Header, 4=Detail, 5=Group Footer, 6=Column Footer, 7=Page Footer, 8=Summary.
  • EXPR: textul (intre ghilimele) la etichete, expresia la campuri, expresia de grupare la banda OBJCODE=3. PAGEBREAK=".T." pe OBJCODE=3 => pagina noua per grup.
  • FONTFACE/FONTSIZE/FONTSTYLE (1=bold); obiectele au MODE=1.
  • Aliniere: la etichete (OBJTYPE=5) PICTURE = "" stanga, "@I" centrat, "@J" dreapta; la campuri (OBJTYPE=8) OFFSET = 0 stanga, 1 dreapta, 2 centrat.
  • Numere: EXPR = transform(camp, get_mask(14, gnpa)) (ca rapoartele existente). _PAGENO, goFirma.Antet, get_mask sunt disponibile la randare.

Asocierea obiect -> banda (capcana centrala)

VFP NU asociaza obiectele dupa ordinea inregistrarilor si NU foloseste VPOS relativ la banda. VPOS este absolut pe pagina, iar banda fiecarui obiect se determina cu intervalele calculate de FFC\_FRXCursor.vcx: fiecarei benzi i se adauga un separator de 2083.333 FRU:

band_START = suma(inaltimilor benzilor precedente) + 2083.333 * (numarul de benzi precedente + 1)
band_STOP  = band_START + HEIGHT

Obiectul apartine primei benzi cu band_START <= VPOS <= band_STOP si se deseneaza la VPOS absolut. Deci, ca sa pui un obiect intr-o banda, calculeaza VPOS = band_START + offset (vezi exemplu mai jos). Verificarea exacta: ruleaza _FRXCursor si citeste BANDS.START/STOP + OBJECTS.BANDLABEL (vezi scriptul de mai jos).

Capcana: continutul benzii Group Header nu se randeaza (nici cu PAGEBREAK pe ea, nici fara; obiectele sunt asociate corect dar nu apar). Solutia care merge: pune continutul per-grup (antet, tabel document, texte, cap de tabel) in Page Header, cu VPOS in intervalul benzii Page Header, si lasa banda Group Header goala (HEIGHT=0) doar cu PAGEBREAK=.T. ca sa declanseze pagina noua per grup. Campurile de grup (nrdoc etc.) se evalueaza corect in Page Header, pentru ca pagina noua incepe cu primul rand al grupului.

Crearea unui raport nou programatic (fara IDE)

COPY STRUCTURE NU e suficient: produce un .frx pe care motorul il raporteaza "is invalid" (lipseste formatul de raport). Corect:

  1. COPY FILE <model>.frx TO <nou>.frx si COPY FILE <model>.frt TO <nou>.frt (pastreaza antetul/memo-ul exact).
  2. USE <nou>.frx EXCLUSIVE apoi ZAP.
  3. APPEND BLANK + REPLACE campurile, per obiect (incepe cu un FUNCTION addrec cu valorile implicite, suprascrie per tip).
  4. Benzile: HEIGHT si OBJCODE; Title/PageFooter pot avea HEIGHT=0.

Exemplu de calcul VPOS pentru benzi Title(0), PageHeader(24000), GroupHeader(0), Detail(1800), GroupFooter(15000), PageFooter(0): PH_START=2083.333, GH_START=28166.666, DETAIL_START=30250, GF_START=34133.333. Obiectele din Page Header: VPOS=2083.333+offset.

Rulare headless (obligatoriu .FXP)

vfp9.exe -A "<script.prg>" deschide des editorul si nu scrie log (proces viu, log gol). Corect: precompileaza intai (COMUN\utile\Teste\_precompile.ps1 -Prg <script.prg>), apoi vfp9.exe -A "<script.FXP>" (fara -T). Prima linie: SET SAFETY OFF. Pune ON ERROR DO ... WITH ERROR(), MESSAGE(), PROGRAM(), LINENO() care scrie in log si QUIT, altfel orice eroare deschide un dialog nativ si blocheaza pana la timeout.

Verificarea ca raportul e valid si arata corect

  • Validitate: FoxBin2Prg.EXE "<raport>.frx" "" "" "" 1 0 1 trebuie sa produca .fr2.
  • Continut: SELECT <cursor> + REPORT FORM <raport> TO FILE <txt> ASCII NOCONSOLE si cauta in <txt> antetul, coloanele, totalurile (TO FILE fara ASCII scrie binar).
  • Aspect: REPORT FORM <raport> PREVIEW NOWAIT, apoi muta fereastra copil "Print Preview" (MoveWindow) ca sa nu acopere pagina si fa screenshot pe fereastra copil cu titlul raportului (PrintWindow). Fara mutarea barei, jumatatea de sus a paginii e mascata de umbra ei.

Capcane

  • COPY STRUCTURE da un .frx invalid; foloseste COPY FILE + ZAP (punctul de mai sus).
  • Continutul benzii Group Header nu se randeaza; muta-l in Page Header (punctul de mai sus).
  • LOCAL laFields + AFIELDS(laFields, ...) da eroarea 232 "not an array"; declara LOCAL ARRAY laFields[1,1].
  • Fara ON ERROR ... QUIT, o eroare intr-un script headless deschide un dialog nativ si pare "agatat" (proces viu, CPU ~0, log gol).
  • vfp9.exe -A "<script>" pe .prg (nu .FXP) deschide editorul; ruleaza .FXP.
  • Diacriticele se scriu ca octeti cp1250 (in .prg le construiesti cu CHR()), nu cu Edit/Write. Setul de caractere se declara pe fiecare obiect text/camp prin DOUBLE=.T. + RESOID=238 (Central European); pentru rapoarte fara diacritice, RESOID=0 si texte ASCII.
  • Fundal pe un cap de tabel: FILLRED/GREEN/BLUE + FILLPAT=1 si MODE=0 - la MODE=1 (transparent) fundalul nu se deseneaza.
  • Cursorul referit de raport trebuie sa fie cel selectat la Report Form; altfel expresiile dau "Variable not found".
  • VFP 9 nu face word-wrap la etichete: liniile lungi se taie la latime; pune CHR(13) explicit in textul etichetei (intre ghilimele) pentru linii multiple.