[QMacros]-基本使用方法说明

1、创建一个TQMacroManager对象,它用来管理所有的宏。后面所有的操作都必需基于它。

[Delphi]

FMacroMgr:=TQMacroManager.Create;

[C++]

FMacroMgr=new TQMacroManager;

2、将基本的宏入栈,注意确定宏的类型。具体请参考主题中的【QMacros宏的值稳定性选项详解】一文的说明。

(1)、入栈常量

[Delphi]

FMacroMgr.Push(宏名称,宏取值)

[C++]

FMacroMgr->Push(宏名称,宏取值);

(2)、入栈通过函数动态返回值的宏

首先,我们需要定义一个宏的取值函数,目前只支持类的成员函数,首先看下回调函数的类型说明。

[Delphi]

/// <summary>查找动态宏的值时的通过回调函数获取相应的值</summary>
/// <param name="AMacro">宏</param>
/// <param name="AQuoter">引号类型,值可能是#0(\0)或英文的单引号或双引号</param>

TQMacroValueFetchEvent = procedure(AMacro: TQMacroItem; const AQuoter: QCharW)

[C++]

/// <summary>查找动态宏的值时的通过回调函数获取相应的值</summary>
/// <param name="AMacro">宏</param>
/// <param name="AQuoter">引号类型,值可能是#0(\0)或英文的单引号或双引号</param>
typedef void __fastcall (__closure *TQMacroValueFetchEvent)(TMacroItem *AMacro,const WideChar &AQuoter);

根据上面的声明,我们声明自己的回调函数实现,然后通过Push函数入栈。入栈时,可以为函数指定一个用户自定义的附加数据,在回调函数中可以通过TQMacroItem的Value.Value的Tag成员来访问。

入栈回调函数实现的宏时,再次强调需要注意其函数值的稳定性。默认值是考虑最糟糕的情况,使用的mvVolatile,但实际上,如果在一次替换操作中,其值是不变的,那么,mvStable是最佳的选择。如果无论何时始终不变,那么直接调用第一种方式Push我想更合适,或者设定类型为mvImmutable。

我们看下这种Push方法的声明:

[Delphi]

/// <summary>入栈指定名称和值的宏定义</summary>
/// <param name="AName">宏名称</param>
/// <param name="AOnFetchValue">获取宏对应的值时调用的回调函数</param>
/// <param name="AVolatile">函数返回值的稳定性</param>
/// <param name="ATag">用户附加的标签数据</param>
procedure Push(const AName: QStringW; AOnFetchValue: TQMacroValueFetchEvent;
      AVolatile: TQMacroVolatile = mvVolatile; ATag: IntPtr = 0);

[C++]

/// <summary>入栈指定名称和值的宏定义</summary>
/// <param name="AName">宏名称</param>
/// <param name="AOnFetchValue">获取宏对应的值时调用的回调函数</param>
/// <param name="AVolatile">函数返回值的稳定性</param>
/// <param name="ATag">用户附加的标签数据</param>
void __fastcall Push(const UnicodeString &AName,TQMacroValueFetchEvent AOnFetchValue,TQMacroVolatile AVolatile=mvVolatile,NativeInt ATag=0);

对于Delphi 2007及更早的版本,UnicodeString替换为WideString,后面的代码规则相同,请自行脑补。

3、执行模板的编译及替换操作

(1)、简化版接口

TQMacroManager提供了两个Replace函数,分别对应于两个版本的替换函数。其中简化版的接口定义如下:

[Delphi]

/// <summary>使用宏定义替换指定的文本</summary>
/// <param name="AText">要被替换的文本</param>
/// <param name="AMacroStart">宏定义起始字符,可以与结束字符不同</param>
/// <param name="AMacroEnd">宏定义结束字符</param>
/// <param name="AFlags">标志位,可取 MRF_IN_DBL_QUOTER 和 MRF_IN_SINGLE_QUOTER 的组合</param>
/// <returns>返回替换完成的结果字符串</returns>
function Replace(const AText: QStringW; AMacroStart, AMacroEnd: QStringW;const AFlags: Integer = 0): QStringW; overload;

[C++]

/// <summary>使用宏定义替换指定的文本</summary>
/// <param name="AText">要被替换的文本</param>
/// <param name="AMacroStart">宏定义起始字符,可以与结束字符不同</param>
/// <param name="AMacroEnd">宏定义结束字符</param>
/// <param name="AFlags">标志位,可取 MRF_IN_DBL_QUOTER 和 MRF_IN_SINGLE_QUOTER 的组合</param>
/// <returns>返回替换完成的结果字符串</returns>
UnicodeString __fastcall Replace(const UnicodeString &AText,UnicodeString AMacroStart,UnicodeString AMacroEnd,const int AFlags=0);

此函数将直接编译并完成替换后释放编译结果。

(2)、完整版本

完整版本由用户自己控制编译和替换过程,从而实现一次编译,多次运行,避免重复的编译开销,加快批量替换时的效率。

编译操作由函数Complie负责完成,我们看它的参数会发现和上面的Replace简化版实现几乎完全一致,唯一的不同是返回了一个TQMacroComplied类型的对象,这个对象在你不需要时,需要手动释放,以避免内存泄露。

替换操作由函数Replace的一种重载实现,唯一的参数是Complie返回的对象实例。

一般情况下,我们不推荐在Complie编译后,再入栈新的宏定义,因为它会引起在Replace时执行一遍宏类型检查,以确保生成正确的结果。

我们看一下这两个函数的声明:

[Delphi]

/// <summary>使用宏定义替换指定的文本</summary>
/// <param name="AText">要被替换的文本</param>
/// <param name="AMacroStart">宏定义起始字符,可以与结束字符不同</param>
/// <param name="AMacroEnd">宏定义结束字符</param>
/// <param name="AFlags">标志位,可取 MRF_IN_DBL_QUOTER 和 MRF_IN_SINGLE_QUOTER 的组合</param>
/// <returns>编译成功,返回编译中间结果句柄,失败,返回空,返回的TQMacroComplied对象需要上层手工释放</returns>
function Complie(AText: QStringW; AMacroStart, AMacroEnd: QStringW;const AFlags: Integer = 0): TQMacroComplied;

/// <summary>使用指定的编译结果执行一次替换操作</summary>
/// <param name="AHandle">使用Complie函数编译的中间结果</param>
/// <returns>返回替换结果</returns>
function Replace(AHandle: TQMacroComplied): QStringW; overload;

[C++]

/// <summary>使用宏定义替换指定的文本</summary>
/// <param name="AText">要被替换的文本</param>
/// <param name="AMacroStart">宏定义起始字符,可以与结束字符不同</param>
/// <param name="AMacroEnd">宏定义结束字符</param>
/// <param name="AFlags">标志位,可取 MRF_IN_DBL_QUOTER 和 MRF_IN_SINGLE_QUOTER 的组合</param>
/// <returns>编译成功,返回编译中间结果句柄,失败,返回空,返回的TQMacroComplied对象需要上层手工释放</returns>
TQMacroComplied * __fastcall Complie(UnicodeString AText,UnicodeString AMacroStart,UnicodeString AMacroEnd,const int AFlags=0);

/// <summary>使用指定的编译结果执行一次替换操作</summary>
/// <param name="AHandle">使用Complie函数编译的中间结果</param>
/// <returns>返回替换结果</returns>
UnicodeString __fastcall Replace(TQMacroComplied *AHandle);

4、释放Complie返回的结果(如果不为空),使用Delphi(Free或Dispose或FreeAndNil或由QString提供的FreeObject)或C++的delete即可。

好了,我想基本的使用步骤已经说的比较清楚了。更高级的主题咱们另章讨论。

 

 

分享到: