2014年12月24日水曜日

FireMonkey の Interface で提供されている機能をオーバーライドする方法

Delphi / Appmethod Advent Calendar 2014 12/24 の記事です


12/24 00:43 頃追記!
inline 指令が意味ないとのことです!
ソース内に書きました!


みなさん! FireMonkey 使ってますか!?
FireMonkey 使ってみると解るんですけど、痒いところに手が届かない事ありますよね!!
とはいえ、FireMonkey ではプラットフォームに依存するクラスは implementation の下に書いて、外出ししてないから置き換えられないよお!って事、良くありますよね。

ですが! FireMonkey には、サービスを置き換えるための仕組みがあります。
クラスそのものを置き換える事はできないのですが、その実体を提供している IFMXxxxx として提供されているサービスを置き換えられます!
今回は、その手法を紹介します。

基本的にはどのサービスも置き換えられるのですが、ここでは簡単のために IFMXSystemFontService を置き換えてみました(必要なメソッドが2つしかないので)。
デフォルトのフォント名を書き換えることで、下記の図のように設計時と実行時のフォントが変わります。
(上が設計時、下が実行時)
わ、解りづらいwww



詳しくは下記のソース内のコメントを参照してください!

unit FMX.SystemFontService;
 
interface
 
uses
FMX.Platform;
 
type
// TInterfacedObject と目的のサービスのインターフェースを継承する
TFMXSystemFontServiceHook = class(TInterfacedObject, IFMXSystemFontService)
private var
// 元々 FMX が登録していたサービスを保持する変数
FOrgFMXSystemFontService: IFMXSystemFontService;
protected
// コンストラクタの中でサービスを置き換える
constructor Create;
public
// 置き換えたいサービスが実装すべきメソッド
{ IFMXSystemFontService }
function GetDefaultFontFamilyName: String;
function GetDefaultFontSize: Single; inline; // inline ついてはメソッド内に
public
// これを呼ぶとコンストラクタを呼べる!
// 今回は Initialization で呼ぶ
class procedure RegistService;
end;
 
implementation
 
var
// このサービスのインスタンスを保持する
SystemFontServiceHook: TFMXSystemFontServiceHook = nil;
 
{ TFMXSystemFontServiceHook }
 
constructor TFMXSystemFontServiceHook.Create;
begin
inherited;
 
// オリジナルの Interface を取り出して自分自身と置き換えてしまう!
if
TPlatformServices.Current.SupportsPlatformService( // 取り出し
IFMXSystemFontService,
IInterface(FOrgFMXSystemFontService))
then begin
// オリジナルを削除
TPlatformServices.Current.RemovePlatformService(IFMXSystemFontService);
// 自分を登録しちゃう
TPlatformServices.Current.AddPlatformService(IFMXSystemFontService, Self);
end;
end;
 
function TFMXSystemFontServiceHook.GetDefaultFontFamilyName: String;
begin
// 元々のサービスが返す値を変えちゃう!
Result := 'メイリオ';
end;
 
function TFMXSystemFontServiceHook.GetDefaultFontSize: Single;
begin
// 元々のサービスの値を返すこともできる
// 置き換える予定の無いメソッドについては inline 指定をすると
// 呼び出しオーバーヘッドが少なくなる
// と思ったのですが、そんなことは無いそうです!!
// 詳しくは、Lyna さんのこのツイートをご覧ください
Result := FOrgFMXSystemFontService.GetDefaultFontSize;
end;
 
// Initialization で↓このメソッドを呼んでコンストラクタを呼び出す
// class constractor でも可能
// これによって、このユニットをプロジェクトを追加するだけで自動的に置き換わる!
class procedure TFMXSystemFontServiceHook.RegistService;
begin
if (SystemFontServiceHook = nil) then
SystemFontServiceHook := TFMXSystemFontServiceHook.Create;
end;
 
initialization
TFMXSystemFontServiceHook.RegistService;
 
end.

ということで、本日はクリスマスイブです!
なのに、こんなブログを書きました!書いたのは23日だけど!!

0 件のコメント:

コメントを投稿