Delphi XE2: Is there a predefined conditional to identify VCL and FireMonkey?
Asked Answered
W

6

14

In Delphi XE2, we have use

{$ifdef Win32}
{$ifdef Win64}

to identify which platform we are in.

Is there any predefined conditional that may identify VCL and FMX?

Wavelength answered 11/10, 2011 at 1:32 Comment(3)
No, you should define your own.Spell
Why is this needed? Something smells a bit fishy to me.Hein
one might want to use a unit with common functionality in both vcl and fmx applications, nothing fishy about that. like: Uses {$IFDEF FMX} FMX.Forms {$ELSE} Vcl.Forms;{$ENDIF}Nerveracking
A
12

As others says, there is not a conditional directive to determine if your application is VCL or FireMonkey. I think the most reliable way to determine if your app is FireMonkey or VCL is using a function instead of a conditional directive.

Something like

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;
Agonizing answered 11/10, 2011 at 2:25 Comment(4)
@Craig, obviously this code requires which the forms unit must be added, about the scope you don't need add the "VCL." or "FMX." this is resolved internally by delphi. So if you uses Formsor Vcl.Forms the code will work ok. And finally about your last comment that's depend of the kind of application, this answer suggests use a function as alternative to the use of a conditional directive.Agonizing
This code requires you to use Forms and not Vcl.Forms. If you explicitly use Vcl.Forms or Fmx.Forms then you've already decided on the platform in the uses clause for the unit, and thus already have a conditional way to check the target widgetset.Lighterman
Also, since the TApplication you're referring to can't change at runtime, using TRttiContext is completely unnecessary. You could simplify IsFireMonkeyApp to Result := {$IF DECLARED(TFmxObject)}True{$ELSE}False{$IFEND}; and it would have the exact same behavior.Lighterman
Better to change the above to Result := GetClass('TFmxObject') <> nil;, as this does not require to have FMX.Types is scope.Ratiocinate
B
13

Although not documented you can have VCL and Firemonkey in the same application.

There is no compiler define.

If you're building something that needs to be both VCL and Firemonkey I would recommend separation of the units.

A possible way:

  • MyLibrary.X.pas - Common Code that both VCL, and Firemonkey would uses.
  • MyLibrary.Vcl.X.Pas - Vcl Specific Code
  • MyLibrary.Fmx.X.Pas - Fmx Specific Code

Mixing UI code from two different frameworks in the same unit is not a good idea. It will link in the other library when it's not needed.

Bushire answered 11/10, 2011 at 2:36 Comment(0)
A
12

As others says, there is not a conditional directive to determine if your application is VCL or FireMonkey. I think the most reliable way to determine if your app is FireMonkey or VCL is using a function instead of a conditional directive.

Something like

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;
Agonizing answered 11/10, 2011 at 2:25 Comment(4)
@Craig, obviously this code requires which the forms unit must be added, about the scope you don't need add the "VCL." or "FMX." this is resolved internally by delphi. So if you uses Formsor Vcl.Forms the code will work ok. And finally about your last comment that's depend of the kind of application, this answer suggests use a function as alternative to the use of a conditional directive.Agonizing
This code requires you to use Forms and not Vcl.Forms. If you explicitly use Vcl.Forms or Fmx.Forms then you've already decided on the platform in the uses clause for the unit, and thus already have a conditional way to check the target widgetset.Lighterman
Also, since the TApplication you're referring to can't change at runtime, using TRttiContext is completely unnecessary. You could simplify IsFireMonkeyApp to Result := {$IF DECLARED(TFmxObject)}True{$ELSE}False{$IFEND}; and it would have the exact same behavior.Lighterman
Better to change the above to Result := GetClass('TFmxObject') <> nil;, as this does not require to have FMX.Types is scope.Ratiocinate
A
4

There is no compiler directive because technically there is no such thing as a firemonkey application or a vcl application. Only applications which make use of these technologies. An application can use fxm or vcl or both or neither (eg. a console app). This is a bit like asking if it is an SQL application. You can of course programatically check the ancestry of individual forms to see which framework they inherit from. Again, inside a unit that has no associated form, this has no meaning.

Aquino answered 25/10, 2011 at 8:38 Comment(0)
E
3

There does not seem to be a compiler define specifically for VCL/FireMonkey. You would need to create your own.

A list of predefined conditionals can be found in the documentation.

Expander answered 11/10, 2011 at 1:54 Comment(2)
Checking the platform defines is not reliable, because you can create for example a OSX App with GUI without Firemonkey as is shown here #7442631Agonizing
@RRuz: Fair enough. Edited my response.Expander
U
2

Abbrevia supports both the VCL and CLX using this kind of split:

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.

To add FireMonkey support, I'd add a file like this:

FmxAbUnit1.pas:

{$DEFINE UsingFMX}
unit FmxAbUnit1;
{$I AbUnit1.pas}
{$ENDIF}

and then make whatever conditional changes I need to AbUnit1.pas.

It's not a nice clean split like Robert's suggestion, but the advantage is that all of your editing occurs in a single file, and the conditional define is handled automatically, so it doesn't need to appear in the project options. Who ever uses your library just includes the appropriate unit to decide which one they want to use. You could probably take advantage of unit scoping too, by naming the files Fmx.AbUnit1.pas and Vcl.AbUnit1.pas, but I think Embarcadero discourages that.

Ummersen answered 11/10, 2011 at 19:4 Comment(2)
Quite nice solution. But does Help insight handle this construction when FMX is defined? At least in XE2 it gets helpless when editing included files.Lona
@Lona I don't use FMX, so I can't say. Under XE1, simple tests work, but it's only picking up some of the changes to the unit after I close and re-open the project.Lighterman
C
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}

It tests if corresponding namespace was declared using IF compilation directive

As FMX isn't mutually exclusive with VCL, there may be a need to add following branches:

{$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'}
Chronometer answered 3/12, 2019 at 6:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.