はじめに
Windows 10がリリースされてもうすぐ2か月。無料アップグレード通知を無視してやり過ごしてきたけれど、Windows 10対応の開発ツールも出てきました。Windows 3.1の時代から永くWindows開発をサポートしてきたDelphiもそのひとつです。
Delphiといえば、20世紀の言語ではないか?と思う方もいるかと思いますが、最近では、マルチデバイス開発ツールへと大きく変容して、活発に新バージョンをリリースしています。変容といっても、昔からのコンポーネントのドラッグ&ドロップは健在だし、なつかしいTEditやTButton、TDataSourceなどのコンポーネントはそのまま使えてしまいます。
今回は、以前作成したアルバムアプリをWindows 10対応するように修正を加えてみます。さらに、マルチデバイス対応の機能を使って、同じアプリをiOS、Androidのマルチデバイスにも展開してみようと思います。
まずはVCLでWindows 10対応
VCLとFireMonkey
いまどきのDelphi(C++でDelphiと同じようなビジュアル開発ができるC++Builder、この2つを使えるスイート製品RAD Studioも同様)には、2つのコンポーネントフレームワークが用意されています。VCLとFireMonkeyです。
VCLは、初代Delphiからずっと搭載されているコンポーネントで、Windows APIをラップしたものです。200以上のコンポーネントがあると言われていますが、数えたことはありません。以前のパッケージには、こんなポスターが付いていたこともありました。
一方、FireMonkeyは、マルチデバイス対応のコンポーネントで、現在、Windows、Mac OS X、iOS、Androidに対応しています。それぞれのネイティブコンパイラがネイティブコードを出力するので、JavaやHTML5とは違って、マルチデバイス対応でもフルネイティブなのです。これについては、後で触れることにします。
VCLのWindows 10コントロール
さて、Windows 10で特徴的なUIといったら「ハンバーガーメニュー」です。ただの3本線が、どうしてバンズとビーフに見えるのか、まったく腑に落ちませんが、とにかく、この3本線のアイコンをクリックすると、メニューがにょろっと出てくるのです。
VCLでどうやってこれを使うのか、早速しらべてみました。
Delphi 10 Seattle(RAD Studio 10 Seattle)には、Windows 10のUIコントロールがいくつか追加されていて、コンポーネントが数多く登録されているツールパレットの[Windows 10]というグループに集められています。
ここに、TSplitViewというコンポーネントがあるので、これをパネルの上に配置します。ハンバーガーアイコンは、ただの画像なのですが、これをクリックしたときに、TSplitViewが動くようにします。
次のようなコードを記述します。
procedure TWin10Form.Image1Click(Sender: TObject); begin if SplitView1.Opened then SplitView1.Close else SplitView1.Open; end;
TSplitViewに表示するメニューは、TActionListを使います。TActionListを使うと、メニュー項目と対応するアクション、それとアイコンを一度に定義できるので便利です。何より、従来のアプリでも使っていた機能なので、前のメニューシステムから必要なものをハンバーガーメニューに持ってこられるため、ひと手間省けます。
特に意味のないメニューですが、数分でこんな感じのハンバーガーができました。
あと、開発環境はまだWindows 8.1を使っているのですが、Delphiのコンポーネントだと、Windows 10でなくてもWindows 10 UIコントロールが動きます。
アルバムアプリを外見からWindows 10対応にする
Windows 10スタイル
Windows 10は、最近流行のフラットデザインを採用していて、今までのグレーの凹凸のはっきりしたUIだとちょっと古臭く感じます。アルバムアプリの場合、Windows 10のダークスタイルのほうが、写真が映えて見えてよさそうです。
Delphi 10 Seattleには、古いVCLアプリケーションでも、スタイルを適用することで、簡単にモダンな外観に変更することができる機能が用意されています。
これまでのアルバムアプリはこんな感じでした。
これにスタイルを適用してみます。[プロジェクト]-[オプション]メニューでオプションダイアログを表示します。[アプリケーション]-[表示]を選択して、カスタムスタイルを選択します。
Windows 10 Blue、Windows 10 Darkなどを選択すると、次のように外観が変わります。
ハンバーガーメニューに変更する
とはいえ、アプリケーションには、相変わらず従来のメインメニューが表示されています。従来のメニューは、キーボードやマウスによる操作が前提のため、タブレットでも動作するいまどきのWindowsアプリでは、何かと問題があります。
アルバムアプリもタブレットで使えるように、ハンバーガーを採用したいところです。
先ほどの実験をアルバムアプリにも適用してみましょう。
まず、メインメニューを表示していたTMainMenuを削除します。メニュー項目の動作は、TActionListを使っていましたから、この削除操作によっても、メニューが呼び出す機能は消えません。TActionListは、初期のDelphiにはなかった機能ですが、アプリケーション内で分散するメニューをアクションというかたちで定義してまとめられて便利です。
最近のバージョンでは、タッチディスプレイのジェスチャーなど、いろいろなコマンド実行操作とコマンドを結びつける手法に、このTActionListを使っています。古いアプリケーションで、メニューを直接コーディングしている場合には、アクション化をしておいたほうがいいようです。
さて、メニューを削除した場所にTPanelを配置します。AlignプロパティをalTopに設定すると、フォームの上部に貼りつきます。色もブルーに変えておきましょう。
ハンバーガーアイコンは、TImageです。ブルーのパネルの上に配置したら、Pictureプロパティで、ハンバーガーの画像を指定します。CursorプロパティをcrHandPointに設定しておくと、アイコンの上でマウスカーソルが指のようなかたちに変わります。
メニューの表示/非表示は、このTImageに対して設定しますが、それは後ほど。
TSplitViewでハンバーガーメニューを実装する
TSplitView
TSplitViewは、ウィンドウの左(あるいは右)からにょろっと出てくるパネルです。つまり、表示/非表示の切り替え時にアニメーションしてくれる四角形です。メニューは、TSplitViewの上に自分で配置しなければなりません。
サンプルによると、TCategoryButtonsを使うことで、複数メニューをアイコンといっしょに表示できます。とはいえ、TSplitViewはパネルの一種なので、UXを混乱させないのであれば、別にどんなコンポーネントを置いても構わないでしょう。
いろいろなコンポーネントが関連してくるので、関係図をまとめてみました。
メニューの動作は、以前のアプリケーションで定義していたものをそのまま使いますので、ここでは特に触れません。
ハンバーガーアイコンにメニュー表示/非表示を実装
さて、いよいよハンバーガーアイコンの機能を実装します。先ほど配置したTImageのOnClickイベントを以下のように記述します。
procedure TAlbum.Image1Click(Sender: TObject); begin if SplitView1.Opened then SplitView1.Close else SplitView1.Open; end;
これでアプリケーションを実行すれば、ハンバーガーメニューの動作を確認できます。TSplitViewのDisplayModeプロパティを変更すると、メニューをオーバーレイ(svmOverlay)にしたり、パネルをスライドさせて表示(svmDocked)させたりするように設定できます。
FireMonkeyでマルチデバイス対応にしてみる
FireMonkeyフレームワーク
外見がすっかりWindows 10ライクになったので、もう十分仕事をした気になってしまいましたが、ここまでわずか数十分の作業なので、もう少し欲を出してみることにしました。
Delphi(そしてC++Builder、RAD Studio)が最近ホットなのは、マルチデバイス対応だからです。アルバムアプリも、いつまでもWindowsに閉じこもってないで、実際に写真を撮っているスマホに対応させたいところです。
でも、その前に、どうしてFireMonkeyだと複数のOSで動くのでしょう。OSが違うのはもちろんですが、画面サイズも解像度も違うのだから、結局UIは別々に作らないとだめなんじゃないか?と思ってしまいます。
FireMonkeyをよく表した図を入手しました。
FireMonkeyはコンポーネントフレームワークなので、アプリケーション開発者は、部品として扱えます。部品と開発者の間には、プロパティ、イベント、メソッドがあり、どのプラットフォームでも共通です。
FireMonkeyの内部には、Windows向けのコードやiOS、Android向けのコードがそれぞれ含まれていますが、開発者はそれを知る必要はないのです。コンパイラはネイティブコンパイラなので、ターゲットOS固有のコードを含むネイティブコードを生成します。開発者から見れば、同じコードからそれぞれのバイナリを、ターゲットを切り替えて作り直しているだけになります。
FireUIマルチデバイスデザイナ
ただ、これでもひとつ問題が残ります。共通のコードが使えるとしても、スマートフォンとタブレットでは画面サイズも違います。デスクトップでは、さらにキーボードやマウスを使うので、操作性がもっと違います。また、Androidでは[戻る]ボタンはOSが提供してくれるのに対し、iOSの場合はアプリ側で実装しなければなりません。iOSのことを考えてアプリ側で[戻る]ボタンを追加しておくと、Androidには余計ですよね。
そこで用意されたのがFireUIです。FireUIは、ひとつのフォームの設計を継承して、複数デバイス向けに対応できるようにしたものです。通常のUI設計(これがマスターフォームになります)をしてから、必要に応じて特定のデバイス向けのUIを、マスターを継承して作ります。
定義するのは、マスターと違う部分だけです。継承関係にありますから、マスターで変更を加えると、継承した子フォームにもその変更は反映されます。親子関係が維持されていないと、後からいろいろ変更が加わったときに、作った分だけ何倍も修正を加えなければならなくなるから、この機能は便利ですね。
FireUIの機能の説明を聞いて、すぐにDelphiのフォーム継承の機能を思い出しました。Delphiはオブジェクト指向で作られていますから、フォームも継承できるのです。ただ、この場合は、コードもすべて継承していますが、FireUIの場合、UIの設計だけを継承しているというにがユニークな点です。コードは引き続きひとつだけなのですね。面白いです。
マルチデバイス向けのマスターフォームを作る
VCL → FireMonkey自動変換ツールもある
さて、もともとVCLで作っていたアプリケーションを、FireMonkeyを使ったマルチデバイス対応にする際に、手作業ではなく簡単に自動変換してくれるツールがあります。Midaと呼ばれるツールなのですが、製品を買うとベーシック版がダウンロードできるようです。有料のフル機能版を使うとかなりの変換をやってくれるそうです。
今回は、UI要素もそれほどないのと、Windows 10対応機能をFireMonkeyだとどうやって作るのかを見てみたいので、Midaを使わずにやってみます。
マルチデバイスアプリケーションを作る
[ファイル]-[新規作成]で、[マルチデバイスアプリケーション]を選択します。これで、マルチデバイスをターゲットとした空のアプリケーションが作成されます。
VCLアプリケーションとデータアクセス部分は共通なので、以前のアプリケーションから、コンポーネントをコピーして持ってきます。写真の情報を表示するコンポーネントを、同じように配置します。
データとの関係付けにはLiveBinding
FireMonkeyアプリケーションでは、データベース対応のDBなんとかというコンポーネントはありません。どのコンポーネントも、LiveBindingでデータ表示が可能だからです。
オブジェクトインスペクタの[ビジュアルにバインド]をクリックすると、Visual LiveBindingが表示されます。ここで、データとコントロールを矢印で結ぶだけで、データ表示の定義は完了です。
マルチデバイス向けのUI設計
StyleBookを使う
VCLにもあったスタイルの機能は、FireMonkeyでより積極的に使われています。ちょうどHTML5に対するCSSのような位置付けで、ビューを定義するための重要な役割を担っています。
FireMonkeyでスタイルを使うには、TStyleBookコンポーネントを用います。コンポーネントをフォーム上にドロップしたら、ダブルクリックしてスタイルデザイナを開きます。ここで、Windows 10のダークスタイルを選択しましょう。
スタイルデザイナで定義を行っただけでは、フォームにスタイルは適用されません。フォームのStyleBookプロパティに配置したTStyleBook(この場合は、StyleBook1)を指定します。
画面右側のタブ「マルチデバイスプレビュー」をクリックすると、複数デバイス向けのプレビューが表示されます。この画面では、さまざまなデバイスで、現在設計しているUIが、どのように表示されるかを確認することができます。
TMultiViewとビヘイビアサービス
FireMonkeyでは、TSplitViewに相当するコンポーネントとしてTMultiViewが用意されています。ただ、TMultiViewはTSplitViewとはちょっと違います。
TSplitViewは、Windows専用なので、Windowsプラットフォームでの動作だけを考慮するだけですみます。一方、FireMonkeyのTMultiViewは、複数プラットフォームが対象となるため、OSごとの差、スクリーンのサイズや向きまで考慮しなければなりません。これをすべて手作業のコーディングで行うと、画面制御だけで膨大なコードになってしまいます。
そこでFireMonkeyでは、ビヘイビアサービスという実行時サービスが裏で動いています。ビヘイビアサービスを使えば、どのようなデバイスで動いているのかを理解し、最適な動作を実行時に選択できます。
TMultiViewは、ビヘイビアサービスを利用するUIコントロールです。つまり、デフォルトの動作であれば、特に指定しなくても、各デバイスで最適な表示にしてくれるのです。
次の図は、TMultiViewを使ったハンバーガーメニュー相当の機能です。
作り方も外見もほぼ同じですが、実際にはマルチデバイスを考慮した最適な表示を行ってくれます。
各デバイス向けのカスタマイズ
FireUIマルチデバイスプレビュー
画面右側のタブ「マルチデバイスプレビュー」をクリックすると、複数デバイス向けのプレビューが表示されます。この画面では、さまざまなデバイスで、現在設計しているUIが、どのように表示されるかを確認することができます。
なるほど、適当に配置したUIは、それぞれのデバイスでは、幅が足りなかったり、画面サイズに全然合致してなかったり、全然ダメですね。マルチデバイス向けのUI設計の配慮が足りませんでした。
レイアウトの仕組みを使う
マルチデバイスでは、画面の向きが縦と横があり、両方をサポートするのか、どちらかのみにするのかを決めなければなりません。例えば縦だけにしたとしても、幅は固定ではないので、柔軟にレイアウトされるように、レイアウト管理のしくみを使います。
FireMonkeyでは、各コンポーネントに、Align、Anchorsといったプロパティがあり、画面のどこに位置するのか、どこを伸ばすのかといったことを指定できます。それぞれのコンポーネントは、パネルなどの上に配置できますから、伸縮する部分をグループ化して、パネルなどの上に置くとよいでしょう。
これらの機能を駆使してみたところ、先ほどよりだいぶマルチデバイス対応のレイアウトになりました。
FireUIマルチデバイスデザイナを使う
とはいえ、どうしても特別なレイアウト調整を加えなければならないデバイスもあります。そういったデバイスについては、FireUIマルチデバイスデザイナで、カスタマイズします。
全部のデバイスについてカスタマイズする必要はなく、マルチデバイスプレビューでチェックしてみて、問題があるな、と気がついたデバイスについてのみ、修正すればよいことに注意してください。
マルチデバイス対応の努力は続く
さて、UIについては問題なく作成できましたが、せっかくなので、デバイスのカメラ機能なども使ってみたいところです。FireMonkeyでは、カメラやGPSなどの機能もコンポーネントによって利用できるので、どんどん拡張できそうです。
本稿では、そこまで触れるスペースはありませんが、以下のような資料が参考になりそうです。
- RAD Studio 10 Seattle機能評価ガイド
- Appmethodでカメラアプリ作成体験(Appmethodは、RAD Studioのマルチデバイス開発機能を無料から利用できるツールです)
また、Delphi(RAD StudioおよびC++Builder)のトライアル版は、こちらからダウンロードできます。