96 lines
5.6 KiB
Markdown
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.
|