Многие хвалят генератор отчетов SREP 1.1 Владимира Карпова, в котором используются RTF шаблоны.
Контакты:
phone: (095)333-63-10 SoftService
E-mail: karpov@softexpress.ru
Пример кода:
#include "srep.ch"
static s1
static s2
static sP2 := "### ### ###.##"
static aParam := {"Fiest parameter", "Second Parametr"}
static sOut := "Out.rtf"
static sRtf := "WordRep.rtf"
//***********************
func main()
//use "..\..\..\..\..\Sample~1\base.dbf" index "..\..\..\..\..\Sample~1\base.cdx" alias "oDB" via "DBFCDX"
//use base.dbf index base.cdx alias oDB via "DBFCDX"
//rddsetdefault("DBFCDX")
dbusearea(.t., nil, "base.dbf", "oDB", .t., .t.)
//oDB->(dbSetIndex("base.cdx"))
RTFReport(sRtf, sOut, "RepHandle") use
return nil
//***********************
func RepHandle(Message, wParam, lParam)
LOCAL RetDate
LOCAL bC
LOCAL OldGroup
? Message, wParam, lParam
IF Message == WM_REP_START_REPORT
s1 := 0
s2 := 0
ELSEIF Message == WM_REP_END_REPORT
//run winword.exe &sOut
? "The End!"
ELSEIF Message ==WM_REP_SUPERSUBGROUP_FOOTER
IF LParam == SECTION_CHECK
IF (oDB->RecNo % 10) == 0
ClipCheck(.t.)
ELSE
ClipCheck(.f.)
END IF
END IF
IF LParam == SECTION_DATA_REQUEST_BY_NAME
ClipData(AllTrim(Str(oDB->RecNo)))
END IF
ELSEIF Message == WM_REP_RTF_HEADER
IF LParam == SECTION_DATA_REQUEST_BY_NAME
? WParam
ClipData("Hi everybody!")
END IF
ELSEIF Message == WM_REP_BODY
IF Lparam == SECTION_DATA_REQUEST_BY_NUM
DO CASE
CASE Wparam == 1
RetDate := AllTrim(oDB->(FIELDGET("FIRST")))+" "+AllTrim(oDB->(FIELDGET("LAST")))
CASE Wparam == 2
RetDate := AllTrim(oDB->(FIELDGET("STREET")))
CASE Wparam == 3
RetDate := AllTrim(oDB->(FIELDGET("CITY")))
CASE Wparam == 4
RetDate := AllTrim(oDB->(FIELDGET("STATE")))
CASE Wparam == 5
RetDate := AllTrim(oDB->(FIELDGET("ZIP")))
CASE Wparam == 6
RetDate := AllTrim(Str(oDB->(FIELDGET("AGE"))))
CASE Wparam == 7
RetDate := Transform(oDB->(FIELDGET("SALARY")), sP2)
END CASE
ClipData(RetDate)
//ELSEIF Lparam == BODY_CHECK
// IF <Some condition>
// BodyRequest(0) //not to print body section with this record
// END IF
ELSEIF Lparam == SECTION_DATA_REQUEST_BY_NAME
ClipData(AllTrim(oDB->(FIELDGET(Wparam))))
ELSEIF Lparam == SECTION_BEGIN
s1 := s1 + oDB->(FIELDGET("SALARY"))
s2 := s2 + oDB->(FIELDGET("SALARY"))
END IF
ELSEIF Message == WM_REP_HEADER
IF Lparam == SECTION_DATA_REQUEST_BY_NUM
ClipData(aParam[Wparam])
END IF
ELSEIF Message == WM_REP_FOOTER
IF Lparam == SECTION_DATA_REQUEST_BY_NUM
ClipData(AllTrim(Transform(s2, sP2)))
END IF
ELSEIF Message == WM_REP_GROUP_HEADER
IF Lparam == SECTION_CHECK
bC := .f.
oDB->(dbskip(-1))
IF !oDB->(bof())
OldGroup := oDB->(FIELDGET("STATE"))
oDB->(dbskip())
ELSE
OldGroup := "hhhhhhhhhhhhhhhhhhhhhhh"
END IF
IF OldGroup != oDB->(FIELDGET("STATE"))
bC := .t.
END IF
ClipCheck(bC)
ELSEIF Lparam == SECTION_DATA_REQUEST_BY_NUM
ClipData(AllTrim(oDB->(FIELDGET("STATE"))))
END IF
ELSEIF Message == WM_REP_GROUP_FOOTER
IF Lparam == SECTION_CHECK
bC := .f.
oDB->(dbskip())
OldGroup := oDB->(FIELDGET("STATE"))
oDB->(dbskip(-1))
IF OldGroup != oDB->(FIELDGET("STATE"))
bC := .t.
END IF
ClipCheck(bC)
ELSEIF Lparam == SECTION_DATA_REQUEST_BY_NUM
IF Wparam == 1
RetDate := AllTrim(oDB->(FIELDGET("STATE")))
ELSEIF Wparam == 2
RetDate := AllTrim(Transform(s1, sP2))
s1 := 0
END IF
ClipData(RetDate)
END IF
ELSEIF Message == WM_REP_MOVE
IF Lparam == MOVE_TOP
oDB->(dbGoTop())
ELSEIF Lparam == MOVE_NEXT
oDB->(dbskip())
END IF
//
//SELF:oDCPBar:Position := SELF:oDCPBar:Position + 1
//SELF:oDCFT_REC:CurrentText := AsString(SELF:oDCPBar:Position)
//SELF:oDCFT_PROC:CurrentText := Transform((SELF:oDCPBar:Position*100)/SELF:oDB:LastRec, "###.## %")
//
ClipCheck(oDB->(Eof())) //It call is nassasary
ELSEIF Message == WM_REP_OPEN_ERROR
? "Can`t open file "+sRtf
ELSEIF Message == WM_REP_CREATE_ERROR
? "Can`t create report file "+sOut
ELSEIF Message == WM_REP_MEM_ERROR
? "Memory error!"
ELSEIF Message == WM_REP_READ_ERROR
? "Read error: " + Str(lParam)
ELSEIF Message == WM_REP_WRITE_ERROR
? "Write error: " + Str(lParam)
ELSEIF Message == WM_REP_SECTION_ERROR
? "Section error with " + Str(lParam) + " " + sRtf
END IF
return nil