Delphi XE2:是否有预定义条件来识别VCL和FireMonkey?

14

在 Delphi XE2 中,我们使用的是

{$ifdef Win32}
{$ifdef Win64}

如何识别我们所在的平台。

是否有预定义的条件语句可以识别VCL和FMX?


不,你应该定义自己的。 - jed
3
为什么需要这个?我觉得有点可疑。 - David Heffernan
3
有些人希望在vcl和fmx应用程序中使用具有常见功能的单元,这并不可疑。例如:Uses {$IFDEF FMX} FMX.Forms {$ELSE} Vcl.Forms;{$ENDIF} - Tuncay Göncüoğlu
6个回答

13

尽管没有记录,但您可以在同一应用程序中使用VCL和Firemonkey。

没有编译器定义。

如果您正在构建需要同时使用VCL和Firemonkey的东西,则建议分离单位。

一种可能的方法:

  • MyLibrary.X.pas - 公共代码,VCL和Firemonkey都会使用。
  • MyLibrary.Vcl.X.Pas - Vcl专用代码
  • MyLibrary.Fmx.X.Pas - Fmx专用代码

在同一单位中混合两个不同框架的UI代码并不是一个好主意。这将在不需要时链接到另一个库中。


12

正如其他人所说,没有一种条件指令可以确定你的应用程序是VCL还是FireMonkey。我认为最可靠的方法是使用函数而不是条件指令来确定你的应用程序是FireMonkey还是VCL。

像这样:

Uses
 Rtti;

function IsVCLApp:Boolean;
begin
 Result:= CompareText(TRttiContext.Create.GetType(TApplication.ClassInfo).QualifiedName,'Vcl.Forms.TApplication')=0;
end;

function IsFireMonkeyApp:Boolean;
begin
 Result:= CompareText(TRttiContext.Create.GetType(TApplication.ClassInfo).QualifiedName,'FMX.Forms.TApplication')=0;
end;

1
@Craig,显然这段代码需要添加表单单元,关于范围,您不需要添加“VCL。”或“FMX。”,这由Delphi内部解决。因此,如果您使用FormsVcl.Forms,代码将正常工作。最后,关于您的最后一条评论,这取决于应用程序的类型,本答案建议使用函数作为替代使用条件指令 - RRUZ
2
这段代码要求您使用Forms而不是Vcl.Forms。如果您明确使用了Vcl.FormsFmx.Forms,那么您已经在单元的uses子句中决定了平台,因此已经有了一种条件检查目标窗口小部件集的方式。 - Zoë Peterson
7
另外,由于您提到的 TApplication 无法在运行时更改,因此使用 TRttiContext 是完全不必要的。您可以简化 IsFireMonkeyAppResult := {$IF DECLARED(TFmxObject)}True{$ELSE}False{$IFEND};,它将具有完全相同的行为。 - Zoë Peterson
1
最好将上面的代码更改为 Result := GetClass('TFmxObject') <> nil;,因为这不需要在作用域中具有 FMX.Types。 - da-soft

4

没有编译器指令,因为技术上讲,并不存在firemonkey应用程序或vcl应用程序,只有使用这些技术的应用程序。 一个应用程序可以使用fxm或vcl或两者都不用(例如控制台应用程序)。 这有点像问它是否是SQL应用程序。当然,您可以通过编程方式检查单个表单的祖先以查看它们继承自哪个框架。 同样,在没有关联表单的单位中,这没有意义。


3

目前似乎没有专门针对VCL/FireMonkey的编译器定义,您需要自己创建。在文档中可以找到预定义条件列表。


1
检查平台定义并不可靠,因为你可以创建一个没有Firemonkey的OSX应用程序,例如在这里所示:https://dev59.com/Pms05IYBdhLWcg3wG-RR - RRUZ
@RRuz:好的,我修改了我的回复。 - Bruce McGee

2

Abbrevia支持VCL和CLX,使用以下方式进行拆分:

QAbUnit1.pas:

{$DEFINE UsingCLX}
unit QAbUnit1;
{$I AbUnit1.pas}

AbUnit1.pas:

{$IFNDEF UsingCLX}
{$DEFINE UsingVCL}
unit AbUnit1;
{$ENDIF}

type
  ...
  TMyWidget = class({$IFDEF UsingVCL}TWinControl{$ENDIF}
                    {$IFDEF UsingCLX}TWidgetControl{$ENDIF})
  ...
  end;

end.

为了添加FireMonkey支持,我会添加像这样的文件:
FmxAbUnit1.pas:
{$DEFINE UsingFMX}
unit FmxAbUnit1;
{$I AbUnit1.pas}
{$ENDIF}

然后在AbUnit1.pas文件中进行任何需要的条件更改。这不像Robert的建议那样干净明了,但好处是所有编辑都在单个文件中进行,并且条件定义是自动处理的,因此无需出现在项目选项中。使用您的库的人只需包含适当的单元即可决定要使用哪个单元。您还可以利用单元作用域,通过将文件命名为和来实现,但我认为Embarcadero不鼓励这样做。

相当不错的解决方案。但是 Help insight 在定义 FMX 时是否能够处理这个结构?至少在 XE2 中,它在编辑包含的文件时变得无助。 - Fr0sT
@Fr0sT 我不使用FMX,所以我无法说。在XE1下,简单的测试可以工作,但只有在我关闭并重新打开项目后才能捕捉到一些单元的更改。 - Zoë Peterson

1

Try this snippet:

{$IF Declared(FMX)}
  // FMX code here. To test this approach you may use {$MESSAGE FATAL 'FMX'}
{$ELSEIF Declared(VCL)}
  // VCL code here. To test this approach you may use {$MESSAGE FATAL 'VCL'}
{$IFEND}

它测试是否使用IF编译指令声明了相应的名称空间
由于FMX与VCL不是互斥的,可能需要添加以下分支:
{$ELSEIF Declared(FMX) and Declared(VCL)}
  // FMX+VCL code here. To test: {$MESSAGE FATAL 'FMX+VCL'}
{$ELSE}
  // no GUI frameworks code here. To test: {$MESSAGE FATAL 'no GUI frameworks'}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接