FireMonkey で「閉じるボタン付きの TabItem」を作ってみました。
これは、そもそもは facebook の Delphi Talks グループで田中さんが「格好いい?「PageControl 」を探しています」というスレッドを立てたので、僕が FireMonkey で作るのはいかがですか!とオススメした所から始まっています。
ということで、FireMonkey でコンポーネントをるのは大変ではないので、作りました
でも、うかうかしているうちに、やましょうさんの前日の Advent Calendar で
> Fmxで作成してみるとわかるのですが、
> delphi+fmxって
> 本当に凄い!!
>
> だってこんなコンポーネントが簡単にできるんですよ。。
> しかも、携帯端末(iosなど)で動くのですから。。
> delphi+fmxって
> 本当に凄い!!
>
> だってこんなコンポーネントが簡単にできるんですよ。。
> しかも、携帯端末(iosなど)で動くのですから。。
と、言いたいことを言われてしまいました!!/(^o^)\
これが Delphi Advent Calendar の怖いところ!!早い者勝ちなので、来年からは書きたいことがあったら、もっと早く書こう…
まあ、それはそれとして、FireMonkey で、コンポーネントを作る方法は大きく分けて次の3段階が必要です。
- スタイルを作る
- コンポーネントを作る
- コンポーネントエディタを作る
FireMonkey の場合、見た目の制御は、ほとんど全部スタイルに任せます。
ですが!スタイルを1から作るのはメンドクサイ!
大体が TShape から派生した TRectangle とか TCircle とか TText とかを組み合わせて作るのですが、そういった簡単な図形以外は TPath を使って作ります。
TPath は SVG とか XAML のパスデータを描画してくれるコントロールです。
今回の「閉じるボタン」は「×」の形をしているので、単純な Shape を組み合わせて作るのは大変です!
なので、今回はズルします!
既に「×」ボタンを持っているコントロールからスタイルを盗みましょう。
そのコントロールとは TClearingEdit です。
ということで、方針が定まったのでスタイルを作っていきます。まずは、TStyleBook をフォームに貼ります。
そして、TStyleBook をダブルクリックしてスタイルエディタを開きます。
そして、デフォルトのスタイルから、まあ、なんでもいいんですが、ここでは構造が簡単な Dark スタイルを読み込みました。
「適用して閉じる」を押して、Style エディタを閉じます。
そして、TForm の StyleBook に StyleBook1 を設定します。
次に TTabControl を Form に貼ります。TTabControl は Common Controls にあります。
貼ったら右クリックしてコンポーネントエディタを開いて TTabItem を1つ作りましょう。
そして、できた TTabItem を右クリックして「カスタムスタイルの編集...」を押します。
すると!先ほど作った TabItem1 専用の Style が自動的に作られます。
これを編集していきます。
そして、先ほど盗んでくる!と言った TClearingEdit の「×」印を盗みます!
これを、そのまま TTabItem に移動しちゃいます。
そして、「適用して閉じる」を押して、スタイルエディタを閉じます。
フォームに戻ってみると……切れてる!!
そうです。「×」印が増えた分、文字が切れてしまったのです。
これは、ソースを修正しないと直せないので、スタイルの編集はここまでにして、次にソースを作っていきます……と、その前に作った Style を保存します。
StyleBook をダブルクリックして、スタイルエディタを開き、「保存」ボタンを押します。
すると、Style がテキストで保存されます。
なので、できあがった tabitem1style1 の "object TLayer" で表されるブロックを残して、あとは消します。
そして、これを保存しておきます。
さて、ではソースを作っていきます。
閉じるボタンが付いている TabItem を、TTabItemWithClose という名前にしました。
一番最初の「[ComponentPlatformsAttribute」はこのコンポーネントがどのプラットフォームで動作するのかを示すモノです。unit FMX.TabItemWithClose;interfaceusesSystem.Classes, FMX.Controls, FMX.TabControl, FMX.StdCtrls;type[ComponentPlatformsAttribute(pidWin32 or pidWin64 or pidOSX32)]TTabItemWithClose = class(TTabItem)public typeTCloseEvent = procedure (Sender: TObject; var ioDoClose: Boolean) of object;private constSTYLE_COLOR_BUTTON = 'closebutton';STYLE_TEXT = 'text';STYLE_TABITEM = 'tabitemstyle';private varFCloseBtn: TCustomButton;FTabControl2: TTabControl;FOnClose: TCloseEvent;protectedprocedure ChangeParent; override;procedure ApplyStyle; override;procedure FreeStyle; override;procedure DoCloseBtnClick(Sender: TObject);function DoSetWidth(var ioValue: Single;iNewValue: single;var ioLastValue: Single): boolean; override;publicclass function Make(const iParent: TTabControl): TTabItemWithClose;property TabControl: TTabControl read FTabControl2;publishedproperty OnClose: TCloseEvent read FOnClose write FOnClose;end;
ここでは、Win32, Win64, OSX32 で動作するとしています。
あとは、閉じるボタンが押されたときのイベントとか、必要な変数・メソッドを定義しています。
ちなみに、StyleLookup をクリックすると出てくるデフォルトの Style は TStyledControl.GetDefaultStyleLookupName で取得します。
なので、ここを Override すると、デフォルトの名前も変わります。
今回の TTabItemWithClose は GetDefaultStyleLookupName を Override しないので、
TabItemWithCloseStyle
という名前のスタイルがデフォルトになり、このスタイルを StyleBook から探すようになります。
なので、先ほど作った Style の名前を TabItemWithCloseStyle とする必要があります。
なので、ここを Override すると、デフォルトの名前も変わります。
今回の TTabItemWithClose は GetDefaultStyleLookupName を Override しないので、
TabItemWithCloseStyle
という名前のスタイルがデフォルトになり、このスタイルを StyleBook から探すようになります。
なので、先ほど作った Style の名前を TabItemWithCloseStyle とする必要があります。
それでは、まず、DoSetWidth というメソッドを見てみます。
ここを修正すると Tab の大きさを変更できます。
function TTabItemWithClose.DoSetWidth(var ioValue: Single; iNewValue: single;var ioLastValue: Single): boolean;beginif (FCloseBtn <> nil) theniNewValue := iNewValue + FCloseBtn.Width * 1.5;Result := inherited;end;
このように変更すると CloseButton の幅の 1.5 倍が足された幅が新しい Tab の幅になります。
それでは、CloseButton はどこで取得するかというと ApplyStyle で取得します。
procedure TTabItemWithClose.ApplyStyle;varCloseBtn: TFmxObject;begininherited;CloseBtn := FindStyleResource(STYLE_COLOR_BUTTON);if (CloseBtn <> nil) and (CloseBtn is TCustomButton) then beginFCloseBtn := TCustomButton(CloseBtn);FCloseBtn.OnClick := DoCloseBtnClick;end;end;
ApplyStyle は、スタイルを適用するときに呼ばれるメソッドです。
そして、FindStyleResource を使うことで、指定したスタイルを「コントロールとして」取得できます。
なので、ソースのように TCustomButton にキャストしてやって、閉じるボタンのインスタンスを保存します。
あとは、FreeStyle メソッドが呼ばれると Style が無効になるので、ここで FCloseButton に nil を代入しています。
また、initialization 部でコンポーネントを登録します。
initializationbeginRegisterFmxClasses([TTabItemWithClose], [TTabControl]);end;
登録しないと、IDE で作成された TTabItemWithClose が起動時やプロジェクト読み込み時にエラーになります。
基本的には、これでできあがりです。
他のメソッドは、僕が Style を一々作り直すのがメンドクサイので、そのための機構が入っています。
これについては、ソースをご覧ください。
そして、最後に、コンポーネントエディタを作らなくてはなりません。
作らないと、IDE で編集すると、TTabItemWithClose は作成されず TTabItem しか作成されません!
ということで、コンポーネントエディタを作りますが……これも DEKO さんが Advent Calendar で発表されているので、そちらをご覧ください!!
僕が書くより、よっぽど詳しいです!!
コンポーネントとして登録する方法なども、リンクがあります!
では、できたコンポーネントが登録されたとして、これを使うためには、先ほど保存した TabItemWithCloseStyle を StyleBook に「追加」を押して、読み込ませます。
それで、適用して閉じたあと、コンポーネントエディタから TTabItemWithClose を作ると……
できました!!!
ちょっと駆け足になったり、はしょったりしましたが、こんな感じで FireMonkey のコンポーネントを作り出せます!
また、記事にすると長いですが、このコンポーネントを作るのに、実質1時間も掛かっていません!
簡単に作れるので、みなさんも、是非 FireMonkey でコンポーネントを作ってみて下さい!
0 件のコメント:
コメントを投稿