标题:求助各位大侠VFP怎样打印备注型字段内容?
只看楼主
wangguowu
Rank: 2
等 级:论坛游民
帖 子:59
专家分:15
注 册:2012-2-15
得分:0 
不是截图,是图文混编,保存成图片,取出就不能识别,请吹水佬和sdta帮忙指点一下!谢谢!
2018-09-05 13:50
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
以下是引用wangguowu在2018-9-5 13:50:01的发言:

不是截图,是图文混编,保存成图片,取出就不能识别,请吹水佬和sdta帮忙指点一下!谢谢!

VFP的“图文”与所说的图文可能不是相同的概念。
你这个“图文混编”的“图”或“文”能转换为VFP的图或文吗?不能的话,要“取出识别”可能吗?
2018-09-05 14:09
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
建议这类数据的输入和输出不要直接用VFP来处理,可以考虑调用第三方的能直接处理这类数据的接口软件。
2018-09-05 14:13
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:0 
一定要用VFP来打印输出也可能的,最彻底的做法就是自己去解释RTF文件,自己绘制打印报表输出,这样做是肯定可以的。有兴趣可以去试试,虽有难度,但一定会有不少收获。
2018-09-05 14:20
wangguowu
Rank: 2
等 级:论坛游民
帖 子:59
专家分:15
注 册:2012-2-15
得分:0 
以下是引用吹水佬在2018-9-5 14:20:19的发言:

一定要用VFP来打印输出也可能的,最彻底的做法就是自己去解释RTF文件,自己绘制打印报表输出,这样做是肯定可以的。有兴趣可以去试试,虽有难度,但一定会有不少收获。
在网上终于找到一个解决示例,但由于自己水平有限,代码很难理解,但不知又是怎么做到的,而且要通过打开报表文件修改表中style字段内容内<VFPData>
    <reportdata name="" type="R" script="" execute="" execwhen="" class="" classlib="" declass="" declasslib=""/>
    <rptctrl class="RTFHandler" expr="XUEXI.解答"/>   
</VFPData>
此处XUEXI.解答是一个表的字段,但报表内看不到该字段在报表上。
代码附上:请能帮助解释一下,谢谢!


** Sample code to run the RTF report / 运行RTF报告的示例代码
** Open our table /打开我们的表
IF NOT USED("xuexi")
    SELECT 0
    USE xuexi AGAIN SHARED ALIAS xuexi
ENDIF
SELECT xuexi
REC = RECNO()
** Create an instance of our ReportListener/创建报告收听器的实例
oRTFListener = NEWOBJECT("CtrlListener","CtrlListener.prg")
** Run the report/运行报表
*REPORT FORM xuexi PREVIEW OBJECT oRTFListener
** Also try the columner report: /也尝试报表
*REPORT FORM xuexi PREVIEW OBJECT oRTFListener
*-报表窗口最大化
 DEFINE WINDOW xuexi FROM 0,0 TO _screen.height/14-1,_screen.width/6;
IN SCREEN system CLOSE FLOAT GROW ZOOM MDI NOMINIMIZE TITLE "[题目练习解答]报表预览器"
activate window xuexi
ZOOM WINDOW xuexi MAX
*report form cjb preview for subs(ksh,1,2)=rdm
report FORM xuexi  PREVIEW OBJECT oRTFListener windows xuexi
release window xuexi
*-结束
以下代码注释部分是我用百度翻译的意思,不准确,请见谅!
***********************************************************
*Classes contained in this PRG: /PRG中包含的类
*CtrlListener - Custom report listener to handle custom controls/CutListEnter自定义报表侦听器来处理自定义控件
*RTFHandler - Handler object for the RTF control used in reports/报表中使用的RTF控件的RTFHANDROR处理程序对象
*Formatrange - Custom class wrapper for the API FORMATRANGE structure/用于API格式范围结构的自定义类包装器
***********************************************************
#DEFINE CHRG_ALL           -1
#DEFINE WM_USER            0x0400
#DEFINE EM_FORMATRANGE     (WM_USER+57)
***********************************************************
***********************************************************
***********************************************************
DEFINE CLASS CtrlListener AS ReportListener&&将类cTrListEnter定义为RealPress侦听器

   oFRX = NULL
   ListenerType = 1  &&列表类型1 报表监听器绘制所有页,然后将输出页传给存储在 _REPORTPREVIEW 中的一个新 Xbase 组件。如果 _REPORTPREVIEW 中没有可用的对象,这个 ListenerType 值不产生任何操作。
   ********************************************************
   PROCEDURE BeforeReport() &&程序 在报表引擎开始处理一个报表表单之前发生
      LOCAL oData AS Object && 局部的数据作为对象
      ** Load the entire FRX into a collection object for  负载这个整个的FRX成A收集对象对于
      ** easy access  容易的接近
      This.oFRX = CREATEOBJECT("Collection") &&创建对象集合
      SET DATASESSION TO (This.FRXDataSession) &&将数据集设置为(FRXDATA)

      SELECT frx
      SCAN &&扫描
         SCATTER MEMO NAME oData  &&从当前记录中复制数据到一组内存变量、一个数组或一个对象,SCATTER 与 COPY TO ARRAY 作用类似。SCATTER 仅复制单个记录(且是当前记录)到一个数组或一组内存变量中,且如果数组或内存变量不存在,则自动创建它们。而 COPY TO ARRAY 可以复制多条记录到数组。
         ** Set the DataSession back to the current. If
         ** not, any obects created in LoadObject( )
         ** will be scoped to the FRX DataSession 将数据集设置回当前。如果不是,任何在LoadObject()将作用于FRX数据集。
         SET DATASESSION TO (This.CurrentDataSession) &&将数据集设置到此
         This.LoadObject(oData) && 加载这个对象
         This.oFRX.Add(oData) && 这增加了(ODATA)
         SET DATASESSION TO (This.FRXDataSession)
      ENDSCAN  &&结束扫描

      SET DATASESSION TO (This.CurrentDataSession)

      RETURN   &&返回
   ENDPROC &&结束程序
   ********************************************************
   PROCEDURE LoadObject(oData)&&加载数据对象程序
      LOCAL oXML AS MSXML2.DomDocument &&本地OXML作为MSXML2.DOM文档
      LOCAL oNode, cClass &&指定要创建的一个或多个局部变量。用逗号分隔
      ** Add a custom handler property to hold handler object 添加自定义处理程序属性来保存处理程序对象
*!*      下面的示例向SCATTER命令创建的对象添加一个新的属性。
*!*       USE customers
*!*       SCATTER NAME oCust
*!*       ADDPROPERTY(oCust,"MyProperty")
*!*    下面的示例向 oMyForm 对象添加了一个属性数组,并且显示它的内容,1 和 "Two"。
*!*    oMyForm = CREATEOBJECT('Form')
*!*    ADDPROPERTY(oMyForm, 'MyArray(2)', 1)
*!*    oMyForm.MyArray(2) = "Two"
*!*    CLEAR
*!*    ? oMyForm.MyArray(1)
*!*    ? oMyForm.MyArray(2)
       ADDPROPERTY(oData,"oHandler",NULL)
      ** Read custom metadata to determine if a custom
      ** handler object is needed    读取自定义元数据以确定是否需要自定义处理程序对象
      IF NOT EMPTY(oData.style) &&如果不是空(ODATA,样式)
         oXML = CREATEOBJECT("MSXML.DomDocument") &&创建对象
         IF oXML.loadXML(oData.style) && 如果OxML.Load XML(ODATA样式)
            oNode = oXML.selectSingleNode("*/rptctrl") &&选择单极子
            IF NOT ISNULL(oNode) &&利用 ISNULL( ) 来确定字段、内存变量或数组元素的内容是否包含一个 null 值,或一个表达式被计算为 null 值。
               ** <rptctrl class="RTFHandler" expr="rtfsample.rtf"/>
               cClass = LOWER(oNode.getAttribute("class")) && 获取属性“类”)
               oData.oHandler = CREATEOBJECT(cClass, This, oData, oNode) &&创建
            ENDIF
         ENDIF
      ENDIF
      oXML = NULL
      RETURN
   ENDPROC
   ********************************************************
   PROCEDURE AdjustObjectSize(nFRXRecno, oObjProperties)
&&nFRXRecno 整数数据类型,指示被绘制的布局元素在报表或标签定义文件(frx 或 lbx)中的记录号。
*!*oObjProperties 一个来源于 Empty 类的对象,其成员提供的值与形状或图片的尺寸调整有关。
      LOCAL oData AS Object
      oData = This.oFRX(nFRXRecno)
      
      ** Check to see if there is a custom handler for this 检查是否有此自定义处理程序对象,并让它处理大小调整。
      ** object and let it handle the size adjustment
      IF VARTYPE(oData.oHandler) = "O"
*返回一个表达式的数据类型。注意:VARTYPE( ) 类似于 TYPE() 函数,但是 VARTYPE() 更快,而且表达式外面不需要引号。 VARTYPE(eExpression [, lNullDataType])
*参数eExpression 指定要返回数据类型的表达式。VARTYPE( ) 返回单个的字符,表明该表达式的数据类型。
         oData.oHandler.HandleObjectSize(This, oData, oObjProperties)
      ENDIF
      
      RETURN
   ENDPROC
   ********************************************************
   PROCEDURE Render(nFRXRecno, nLeft, nTop, nWidth, nHeight, ;
         nObjectContinuationType, cContentsToBeRendered, GDIPlusImage)
*!*    在报表监听器为一个报表或标签中的布局元素准备好提供输出时发生。
*!*    oReportListener.Render(nFRXRecNo, nLeft, nTop, nWidth, nHeight, ;
*!*        nObjectContinuationType, cContentsToBeRendered, GDIPlusImage )
*!*    参数
*!*    nFRXRecno  
*!*    指定报表或标签定义文件(frx 或 lbx)中将被绘制的布局元素的记录号。
*!*    nLeft  
*!*    指定将被绘制的布局元素在当前页上的矩形所在的列坐标,单位时 1/960 英寸(960 dpi)。
*!*    nTop  
*!*    指定将被绘制的布局元素在当前页上的矩形所在的行坐标,单位时 1/960 英寸(960 dpi)。
*!*    nWidth  
*!*    指定将被绘制的布局元素在当前页上的矩形宽度,单位时 1/960 英寸(960 dpi)。
*!*    nHeight  
*!*    指定将被绘制的布局元素在当前页上的矩形高度,单位时 1/960 英寸(960 dpi)。
*!*    nObjectContinuationType  
*!*    指示被绘制元素的 当前延续状态。当布局元素跨越页时,它们将被绘制成多个部分(每页有一部分)。
      LOCAL oData AS Object
      oData = This.oFRX(nFRXRecno)
      ** Check to see if there is a custom handler for this  检查是否有此自定义处理程序对象,并让它处理渲染。如果它返回,则绕过默认行为。
      ** object and let it handle the Render.
      ** If it returns .T. bypass the default behavior
      IF VARTYPE(oData.oHandler) = "O"
         IF oData.oHandler.HandleRender(This, oData, nLeft, nTop, ;
               nWidth, nHeight, nObjectContinuationType, ;
               cContentsToBeRendered, GDIPlusImage)
            NODEFAULT &&
         ENDIF
      ENDIF
      
      RETURN
   ENDPROC&&表示 PROCEDURE 结构的结束
   ********************************************************
   PROCEDURE AfterReport()
*!*    在报表引擎结束一个报表表单的处理后发生。PROCEDURE Object.AfterReport
*!*    参数 无。说明应用于:ReportListener 对象。在报表运行结束,以及最后的 AfterBand 事件之后,报表引擎触发 AfterReport 事件。此时,由 FRXDataSession 属性指定的私有数据工作期仍然包含了这个报表定义文件(frx)的只读副本。打印工作(如果这个报表执行了打印操作)仍然打开。
*!*    在从 AfterReport 返回之后,如果 REPORT FORM 命令中没有使用 NOPAGEEJECT 关键字,则输出将被终止(例如,打印工作已被关闭)。
      ** Clear out all of the objects or the FRX DataSession   清除所有对象或FRX数据将无法走出范围
      ** will not be able to go out of scope
      This.oFRX.Remove(-1) &&数值型。eIndex 表达式的值必须在 1 到集合的 Count 属性之间。如果传递 -1 值, Visual FoxPro 从集合中移去所有的项。
      This.oFRX = NULL
      
      RETURN
   ENDPROC

ENDDEFINE  &&结束定义
***********************************************************
***********************************************************
***********************************************************
DEFINE CLASS RTFHandler AS Custom &&自定义类RTFANTHER

   oForm = NULL
   oFR = NULL
   nTopMargin = 0
   nLeftMargin = 0
   ********************************************************
   PROCEDURE Init(oRL, oData, oNode)
   *Param1, Param2... 参数是可选的,但如果传递了参数,你必须包含一个列出每个参数的 LPARAMETERS 或 PARAMETERS 语句。否则将产生一个错误。在一个对象被创建时发生
      DECLARE Long GdipGetDC IN GDIPLUS ;
         Long graphics, Long @hdc
      DECLARE Long GdipReleaseDC IN GDIPLUS ;
         Long graphics, Long hdc
      DECLARE Long SendMessage IN WIN32API AS SendMessage_String ;
         Long hWnd, Integer Msg, Integer wParam, String @lParam
*!*    注册一个外部共享库中的函数。库是 32-位动态链接库文件(.DLL)。
*!*    DECLARE [cFunctionType] FunctionName IN LibraryName [AS AliasName]   [cParamType1 [@] ParamName1, cParamType2 [@] ParamName2, ...]
*!*    参数
*!*    cFunctionType
*!*    如果有返回值,则表明共享库返回值的数据类型。如果函数没有返回值,则省略 cFunctionType。
*!*    cFunctionType 可以是以下值: cFunctionType 说明
*!*    SHORT 16-位 整数
*!*    INTEGER 32-位 整数
*!*    SINGLE 32-位 浮点数
*!*    DOUBLE 64-位 浮点数
*!*    LONG 32-位 长整数
*!*    STRING 字符串
*!*    OBJECT IDispatch 对象类型 *NEW
*!*    FunctionName
*!*    指定 Visual FoxPro 中要注册的共享库函数名。该参数中传递的函数名要求区分大小写。注意:DLL 函数名可以与 Win32 API 手册中规定的不同。例如,MessageBox 函数应该命名为 MessageBoxA (对于单字节字符)和 MessageBoxW (对于 UNICODE)。如果 Visual FoxPro 不能定位 FunctionName 指定的 DLL 函数,则将字母 A 追加到函数名尾部,并且 Visual FoxPro 用新的函数名重新搜索。
*!*    如果指定的共享库函数与一个 Visual FoxPro 函数同名,或函数名不是一个合法的 Visual FoxPro 名,当注册此函数时,将用 AS 子句分配一个别名,这点在后面将要说明。也可以用 OBJECT 作为一个返回值,例如"DECLARE OBJECT myfunc IN some DLL ..." 虽然 COM 通常没有任何这种格式的 API 。例如:
*!*    DECLARE INTEGER AccessibleObjectFromWindow IN oleacc.dll ;
*!*    integer, integer, string , object @
*!*    IN LibraryName  指定外部共享库名,其中包含用 FunctionName 指定的函数。如果为 LibraryName 指定 WIN32API,则 Visual FoxPro 在Kernel32.dll, Gdi32.dll, User32.dll, Mpr.dll, 和 Advapi32.dll 中搜索 32-位 Windows .dll 函数。
*!*    AS AliasName 为一个与 Visual FoxPro 函数同名或不合法的共享库函数名,指定一个别名。AliasName 不能是 Visual FoxPro 保留字或已经由 Visual FoxPro 注册的共享库函数名。如果给函数指定了别名,可以用别名调用共享库函数。AliasName 不区分大小写。
*!*    cParameterType1[@] ParamName1, cParameterType2[@] ParamName2, ...
*!*    指定传递给共享库函数的参数类型。共享库函数由 cParameterType 指定需要的参数类型。cParameterType 可以为以下某一类型: cParameterType 说明
*!*    INTEGER 32-位 整数
*!*    SINGLE 32-位 浮点数
*!*    DOUBLE  64-位 浮点数
*!*    LONG      32-位 长整数
*!*    STRING  字符串
*!*    如果参数不是共享库中的函数所希望的类型,Visual FoxPro 产生一条错误。Null 值可以传递一个空的字符串。调用函数时,若按引用传递一个参数,必须在这条命令的参数 cParameterType 后面、调用函数相应变量的前面,包含(@)标记。 如果在 DECLARE 中或在调用函数中没有包含 @,参数就按值传递。

      ** NOTE: Prior to SP1 the Top and Left positions in   注意:在SP1之前,顶部和左边的位置在调整对象大小不包括偏移量*打印机边距。现在确定它们以供以后使用。
      ** AdjustObjectSize do not include the offset for the
      ** printer margins. Determine them now for use later.

*!*    VERSION(nExpression) 返回关于正在使用的 Visual FoxPro 版本信息
*!*    参数 nExpression 指定 VERSION( ) 返回有关 Visual FoxPro 的附加信息。若省略 nExpression 参数,则 VERSION( ) 返回 Visual FoxPro 的版本号。
*!*    下表列出了 nExpression 参数及返回的有关 Visual FoxPro 的附加信息。 nExpression 返回的 Visual FoxPro 附加信息
*!*    1  Visual FoxPro 的日期及系列号。
*!*    2  Visual FoxPro 的版本类型:
*!*    0 - 运行版
*!*    1 - 标准版(早期版本)
*!*    2 - 专业版(早期版本)
*!*    3  指出 Visual FoxPro 使用的语言,以下两个字符值表明 Visual FoxPro 所使用的语言:
*!*    00 - 英语
*!*    07 - 俄语
*!*    33 - 法语
*!*    34 - 西班牙语
*!*    39 - 捷克语
*!*    48 - 德语
*!*    55 - 朝鲜语
*!*    86 - 简体中文
*!*    88 - 繁体中文
*!*    4 易于分析的标准格式 Visual FoxPro 版本号。
*!*    对于 Visual FoxPro 8.0 以前版本, 标准格式是 "MM.mm.0000.DDDD" 其中 MM 主版本号, mm 是可增加的次级修订编号, 0000 是固定占位符, DDDD 是四数字的创建该版本的生产日期。
*!*    对于 Visual FoxPro 8.0, 计算产品日期的公式, DDDD, 是 8000 + 从 1998 以来的日数。例如, 8397 代表 1999.02.01
*!*    对于 Visual FoxPro 9.0, 计算产品日期的公式, DDDD, 自 2003.01.01 以来的月数连接上当前月数。例如, 2215 表示 2004.10.15
*!*    Visual FoxPro 8.0 和 9.0 的格式是 "MM.mm.0000.NNNN" 其中 MM 主版本号, mm 是可增加的次级修订编号, 0000 是固定占位符, NNNN 建立号。
*!*    5 "Mmm" 格式的 Visual FoxPro 发布版本,其中 M 是主发布号,mm 是可增加的次级修订编号。例如,VERSION(5) 在 Visual FoxPro 7.0 中返回 700。
*!*     返回值 字符型、数值型
*!*    说明 可使用 VERSION( ) 有条件地执行与特定版本相关的代码。VERSION( )、VERSION(1)、VERSION(3) 和 VERSION(4) 返回字符串;VERSION(2) 和  VERSION(5) 返回一个数值。
      IF VERSION(4) < "09.00.0000.3307"
         This.SetPageMargins() &&设置页面
      ENDIF

      IF PCOUNT() >= 3
*!*    返回传递给当前程序、过程或用户自定义函数的参数的个数。
*!*    PCOUNT( )返回值,数值型.说明  PCOUNT( ) 用于确定有多少参数传递给了当前程序、过程或用户自定义函数
         This.SetUp(oRL, oData, oNode) &&设置
      ENDIF
      
      RETURN
   ENDPROC
   *********************************************************** GetDeviceCaps 获取特定设备的信息,CreateDC创建的
   PROCEDURE SetPageMargins()
   #DEFINE LOGPIXELSX         88
   #DEFINE LOGPIXELSY         90
   #DEFINE PHYSICALOFFSETX    112
   #DEFINE PHYSICALOFFSETY    113
      DECLARE Integer GetDeviceCaps IN WIN32API ;
         Integer, Integer
      DECLARE Long CreateDC IN WIN32API ;
         String lpszDriver, String lpszDevice, ;
         String lpszOutput, String @lpInitData
      DECLARE Integer DeleteDC IN WIN32API ;
         Long hDC
      ** The Top and Left positions we get in AdjustObjectSize  我们在AdjustObjectSize的左上和左位不包括打印机边距的偏移量。
      ** do not include the offset for the printer margins.
      LOCAL hDC
      LOCAL nLogOffsetX, nLogOffsetY
      LOCAL nLogPixelsX, nLogPixelsY
      hDC = CreateDC("WINSPOOL",SET("Printer",3),NULL,NULL)
      IF hDC <> 0
         nLogPixelsX = GetDeviceCaps(hDC,LOGPIXELSX)
         nLogPixelsY = GetDeviceCaps(hDC,LOGPIXELSY)
         nLogOffsetX = GetDeviceCaps(hDC,PHYSICALOFFSETX)
         nLogOffsetY = GetDeviceCaps(hDC,PHYSICALOFFSETY)
         This.nLeftMargin = nLogOffsetX*960/nLogPixelsX
         This.nTopMargin = nLogOffsetY*960/nLogPixelsY
      ENDIF
      DeleteDC(hDC)
   
   ENDPROC
   ***********************************************************
   PROCEDURE SetUp(oRL, oData, oNode)
      ** oRL - Reference to the ReportListener object  引用到RePress侦听器对象
      ** oData - Reference to this controls FRX record   参考此控制FRX记录
      ** oNode - Reference to this controls MetaData    OnDoD-引用此控件元数据
      LOCAL cExpr
      ** Create an instance of the RichText control in a form  在窗体中创建ReXTeX控件的实例
      This.oForm = CREATEOBJECT("Form")
      This.oForm.AddObject("oRTF","OLEControl","RichText.RichTextCtrl")
      ** Create an instance of the FORMATRANGE wrapper class  创建FravaLink包装类的实例
      This.oFR = CREATEOBJECT("formatrange")
      ** These properties keep track of how much text has been  这些属性跟踪页面之间呈现了多少文本。
      ** rendered between pages
      ADDPROPERTY(oData, "nCharPos", 0)
      ADDPROPERTY(oData, "nCharLen", 0)
      ** Get the expression value from the metadata   从元数据获取表达式值
      cExpr = oNode.getAttribute("expr")  &&获取属性
      IF NOT EMPTY(cExpr)
         oData.expr = cExpr
      ENDIF
      
      RETURN
   ENDPROC
   ********************************************************
   PROCEDURE HandleObjectSize(oRL, oData, oProp)
      ** oRL - Reference to ReportListener object  引用到RePress侦听器对象
      ** oData - Reference to controls FRX record 参考数据对照FRX记录
      ** oProp - Reference to oObjProperties from AdjustObjectSize  OpRP-从Actudio对象的大小引用OObjices属性
      LOCAL hDC, nLeft, nTop, nRight, nBottom, cFR
      ** If this is the first time for this record, initialize  如果这是该记录的第一次,则初始化tExtf并重置我们的位置指针
      ** the TextRTF and reset our position pointers
      IF NOT oProp.reattempt
         This.oForm.oRTF.TextRTF = EVALUATE(oData.expr) &&用 EVALUATE( ) 或名表达式来取代使用 & 命令 的宏替换。EVALUATE 和名表达式的执行比宏替换快。
         oData.nCharPos = 0
         oData.nCharLen = LEN(This.oForm.oRTF.Text)
      ENDIF

      hDC = 0
      GdipGetDC(oRL.GDIPlusGraphics, @hDC)
      * GDIPlusGraphics双曲线图形
      ** Set both HDC attributes to the Graphics object 将HDC属性设置为图形对象
      This.oFR.SetHDC(hDC,hDC)
      ** Set the render rectangle to the maximum available height  将渲染矩形设置为最大可用高度
      ** Make sure it includes the page margins  确保它包含页边距
      ** Note TWIPS/Pixels = 1440/960  注意缇/像素=1440/960
      WITH oProp
         IF VERSION(4) < "09.00.0000.3307"
            ** Prior to SP1 you need to add the page margins
            ** to the .Top and .Left properties
            nLeft   = (.left + This.nLeftMargin)*1440/960
            nTop    = (.top + This.nTopMargin)*1440/960
            nRight  = (.left + .width + This.nLeftMargin)*1440/960
            nBottom = (.top + .maxheightavailable + This.nTopMargin)*1440/960
         ELSE
            nLeft   = (.left)*1440/960
            nTop    = (.top)*1440/960
            nRight  = (.left + .width)*1440/960
            nBottom = (.top + .maxheightavailable)*1440/960
         ENDIF         
      ENDWITH
      This.oFR.SetRC(nLeft, nTop, nRight, nBottom)
      ** Set the Page size 设置页面大小
      This.oFR.SetRCPage(0,0, ;
             oRL.GetPageWidth()*1440/960, ;
             oRL.GetPageHeight()*1440/960)
      ** Set the character range. 设置字符范围。
      This.oFR.SetCHRG(oData.nCharPos, CHRG_ALL)
      cFR = This.oFR.data
      oData.nCharPos = SendMessage_String( ;
                      This.oForm.oRTF.HWnd, ;
                      EM_FORMATRANGE, ;
                      -1, ;
                      @cFR)
      This.oFR.data = cFR
      ** Grab the updated rectangle bottom. This is the physical
      ** position the RichText control stopped drawing.   抓取更新的矩形底部。这是RixTeX控件停止绘制的物理位置。
      nBottom = 0
      This.oFR.GetRC(0,0,0,@nBottom)
      ** Was all the RTF Text rendered?  所有RTF文本都被渲染了吗?
      IF oData.nCharPos < oData.nCharLen
         ** If not, force a new page by setting the object height to  如果不是,则通过将对象高度设置为 大于最大可用高度的值
         ** a value higher than the max available height
         oProp.height = oProp.maxheightavailable+1
      ELSE
         ** If so, update the height to the position the RichText  如果是,将高度更新到ReXT文本的位置。控制完成图纸
         ** control finished drawing.
         oProp.height = (nBottom*960/1440)-(oProp.top+This.nTopMargin)
         
         ** The control requires that the cache is cleared when   控件要求缓存何时清除。完成渲染。将null传递给LPARAM。
         ** finished rendering. Pass a NULL to lParam.
         SendMessage_String( ;
                      This.oForm.oRTF.HWnd, ;
                      EM_FORMATRANGE, ;
                      -1, ;
                      NULL)
      ENDIF
      ** Tell the report engine to read the updated values  告诉报表引擎读取更新的值
      oProp.reload = .T.
      ** Release the Graphics device context created earlier  释放先前创建的图形设备上下文
      GdipReleaseDC(oRL.GDIPlusGraphics, hDC)
      
      RETURN
   ENDPROC
   ********************************************************
   PROCEDURE HandleRender(oRL, oData, nLeft, nTop, nWidth, nHeight, ;
         nObjectContinuationType, cContentsToBeRendered, GDIPlusImage)
      ** Do nothing. We already rendered. 什么也不做。我们已经准备好了。
      RETURN .T.
   ENDPROC

ENDDEFINE
***********************************************************
***********************************************************
***********************************************************
DEFINE CLASS formatrange AS Custom  &&自定义类窗格范围

#DEFINE FR_SIZEOF          0x0030
#DEFINE FR_HDC            (0x0000 + 1)
#DEFINE FR_HDCTARGET      (0x0004 + 1)
#DEFINE FR_RC_LEFT        (0x0008 + 1)
#DEFINE FR_RC_TOP         (0x000C + 1)
#DEFINE FR_RC_RIGHT       (0x0010 + 1)
#DEFINE FR_RC_BOTTOM      (0x0014 + 1)
#DEFINE FR_RCPAGE_LEFT    (0x0018 + 1)
#DEFINE FR_RCPAGE_TOP     (0x001C + 1)
#DEFINE FR_RCPAGE_RIGHT   (0x0020 + 1)
#DEFINE FR_RCPAGE_BOTTOM  (0x0024 + 1)
#DEFINE FR_CHRG_CPMIN     (0x0028 + 1)
#DEFINE FR_CHRG_CPMAX     (0x002C + 1)

   data = 0h00
   ********************************************************
   PROCEDURE Init()
      This.data = REPLICATE(0h00,FR_SIZEOF)&& REPLICATE 复制
   ENDPROC
   ********************************************************
   PROCEDURE SetHDC(nHDC,nHDCTarget)
      WITH This
      .data = STUFF(.data, FR_HDC,      4, BINTOC(nHDC,"4SR"))
      .data = STUFF(.data, FR_HDCTARGET,4, BINTOC(nHDCTarget,"4SR"))
      ENDWITH
   ENDPROC
*!*     返回一个字符串,此字符串是通过用另一个字符表达式替换现有字符表达式中指定数目的字符得到的。STUFF(cExpression, nStartReplacement, nCharactersReplaced, cReplacement)
*!*     参数cExpression 指定要在其中进行替换的字符表达式。
*!*    nStartReplacement指定在 cExpression 中开始替换的位置。
*!*    nCharactersReplaced 指定要替换的字符数目。如果 nCharactersReplaced 是 0,则该替换字符串 cReplacement 插入到 cExpression 中。
*!*    cReplacement 指定用以替换的字符表达式。如果 cReplacement 是空字符串,则从 cExpression 中删除用 nCharactersReplaced 指定的字符数目
*-
*!*    将一个数字值转换成一个二进制字符表示。BINTOC(nExpression [, eFlags])
*!*     参数nExpression 指定要转换的值。对于 eFlags 设置为 1、2 或 4 时,该值应该是一个整数。其它的,该表达式的数据类型基于 eFlags 的设置。
*!*    eFlags 指定返回串字符的长度。eFlags 决定可以指定的 nExpression 值。eFlags 可以是数值或字符。下表列示了 eFlags 的允许值以及相应的  nExpression 值的范围: eFlags nExpression 范围
*!*    1 –128 到 127
*!*    2 –32,768 到 32,767
*!*    4 –2,147,483,648 到 2,147,483,647
*!*    这是默认设置。8
*!*     nExpression 的范围依赖于它的类型。该选项只支持数值(numeric)、浮点(float)、双精度(double)和货币(currency)数据类型。有关数值、浮点、双精度和货币型数据类型的范围,参见 Visual FoxPro 数据和字段类型。
*!*    BINTOC( ) 为该串返回 8 个字节。
*!*    F nExpression 被作为一个 浮点型字段类型 并且 BINTOC( ) 返回 4 个字节。
*!*    B nExpression 被作为一个 双精度型字段类型 并且 BINTOC( ) 返回 8 个字节。
*!*    R 反转作为结果的二进制表达式。
*!*    S 防止数值的符号位被旋转(BITXOR)。
*!*     如果省略该参数,BINTOC( ) 返回一个由四个字符组成的字符串。
*!*    返回值 字符型。BINTOC( ) 返回一个二进制字符表达式。
*!*    说明 eFlags 参数可以是数值或字符。当其它设置相互排斥时,'R' 和 'S' 设置是可添加的。字符设置的传递不区分大小写(例如,'R' 或 'r')。下列示例展示了 eFlags 参数的不同用法。
*!*    ? BINTOC(1,1)
*!*    ? BINTOC(1000,"2")&& 与 BINTOC(1000,2) 相同
*!*    ? BINTOC($12.34,8)
*!*    ? BINTOC(1, "4RS")&& 与 BINTOC(1,"RS") 相同
*!*    ? BINTOC(-100, "Fr")
*!*     可以使用 BINTOC( ) 通过传递一个数字 eFlags 参数来为包含整型数据的数值型字段缩小索引尺寸。例如,一个叫 nPartCode 的数值型字段可能包含了从 1 到 32,767 的整数值,对应一种零件的分类编码。BINTOC( ) 转换该数值型字段中的值到一个较少的字符表示。例如,下列命令用一个双字符的索引关键字创建一个索引:
*!*    INDEX ON BINTOC(nPartCode,2) TAG PartCode
*!*    当使用 BINTOC( ) 创建一个 8 字节索引时,应当使用 8 而不是 "B"。如果 nExpression 是一个整型,对于 4 字节结果,应当使用 4。其它的,对于浮点类型,应当使用 'F'。
*!*    当使用一个可能需要转换(到或自) Win32 结构成员的 Win32 API 例程时,也能用到 BINTOC( )。当用于索引时,BINTOC( ) 需要为二进制表达式结果适当地处理负数。这通过在高位上使用一个 BITXOR 选项来进行。这也意味着首位最重要。对于 Intel 平台上的 Win32 API 例程,其结构遵循小尾(little-endian)规则(翻译者注:即低字节的寄存器占用低内存地址线),在那里首先保存最不重要的位(用最低位的存储单元)。'R' 和 'S' 设置允许利用 BINTOC( ) 与使用结构的例程更有效地工作。
   ********************************************************
   PROCEDURE SetRC(nLeft, nTop, nRight, nBottom)
      WITH This
      .data = STUFF(.data, FR_RC_LEFT,  4, BINTOC(nLeft,"4SR"))
      .data = STUFF(.data, FR_RC_TOP,   4, BINTOC(nTop,"4SR"))
      .data = STUFF(.data, FR_RC_RIGHT, 4, BINTOC(nRight,"4SR"))
      .data = STUFF(.data, FR_RC_BOTTOM,4, BINTOC(nBottom,"4SR"))
      ENDWITH
   ENDPROC
   ********************************************************
   PROCEDURE GetRC(nLeft, nTop, nRight, nBottom)
      WITH This
      nLeft  = CTOBIN(SUBSTR(.data,FR_RC_LEFT,4),  "4SR")
      nTop   = CTOBIN(SUBSTR(.data,FR_RC_TOP,4),   "4SR")
      nRight = CTOBIN(SUBSTR(.data,FR_RC_RIGHT,4), "4SR")
      nBottom= CTOBIN(SUBSTR(.data,FR_RC_BOTTOM,4),"4SR")
      ENDWITH
   ENDPROC
   ********************************************************
   PROCEDURE SetRCPage(nLeft, nTop, nRight, nBottom)
      WITH This
      .data = STUFF(.data, FR_RCPAGE_LEFT,  4, BINTOC(nLeft,"4SR"))
      .data = STUFF(.data, FR_RCPAGE_TOP,   4, BINTOC(nTop,"4SR"))
      .data = STUFF(.data, FR_RCPAGE_RIGHT, 4, BINTOC(nRight,"4SR"))
      .data = STUFF(.data, FR_RCPAGE_BOTTOM,4, BINTOC(nBottom,"4SR"))
      ENDWITH
   ENDPROC
   ********************************************************
   PROCEDURE SetCHRG(nCPMin, nCPMax)
      WITH This
      .data = STUFF(.data, FR_CHRG_CPMIN, 4, BINTOC(nCPMin,"4SR"))
      .data = STUFF(.data, FR_CHRG_CPMAX, 4, BINTOC(nCPMax,"4SR"))
      ENDWITH
   ENDPROC

ENDDEFINE
*------------------
以下是运行效果


2018-09-06 18:05
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:20 
回复 15楼 wangguowu
这个可以
但用原提供的数据文件测试不正常
2018-09-07 04:49



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-489612-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.426481 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved