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

96 lines
5.6 KiB
Markdown

# 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.