Windows Phoneアプリケーション開発入門

第18回 Windows Phoneでグラデーションのボタンを作ってみよう!(5)

この記事を読むのに必要な時間:およそ 4 分

Microsoft Tech・Ed Japan 2010よりWindows Phone 7ニュース

8月25日より3日間パシフィコ横浜にて開催された,Microsoft社がワールドワイドに展開している最大級の技術コンファレンス「Microsoft Tech・Ed Japan 2010」に参加してまいりました。せっかくですので,はじめに今回のTech・Edについて簡単にレポートしたいと思います。

今回のメインテーマは「クラウド」で,今年から本格稼働を始めたAzureは既に日本での利用実績もあり,各社クラウドの導入が着々と進んでいることを示していました。

私もこのような連載をさせて頂いており,ガジェットに強い興味がある立場として,Windows Phone 7に関して新しい発表があるのでないかと,基調講演をすごく楽しみにしていました。期待通り,Windows Phone 7が登場し,日本初だと思われるWindows Phone 7を使ったデモが実施されました。

Visual Studio 2010 Express for Windows Phoneを使って,あっという間にTwitterクライアントを作り上げていました。 電波状況が悪かったのか,タイムラインがなかなか表示されていませんでしたが,タイムラインが表示された時は拍手喝采でした。

テクニカルセッションでは,高橋忍氏による「Expression Blend 4でデザインするSilverlight 4アプリケーション」は,Expression Blend 4によるSilverlightアプリケーションの開発手法をわかりやすく紹介されていました。Windows Phone 7アプリケーションでサポートされているSilverlightのバージョンは3+αですが,紹介された手法はWindows Phone 7アプリケーション開発にも流用可能でしたので,形を変えて本連載内でもご紹介できればと考えております。

また,Windows Phone 7と今後肩を並べるだろう企業向けモバイルOSのWEC7(Windows Embedded Compact 7)についても,太田寛氏による「最新OS WES7 WEC7 .NET Micro Frameworkによるクラウド時代のデバイスUX開発」にてWEC7を使ったデモが行われておりました。

WEC7の特徴としては,Silverlight for Windows Embeddedのテクノロジが使用でき,Expression BlendでUIを,Visual Studio 2008でロジックをといったUXを意識した開発が組込機器でも可能な点でしょうか。ネットワーク間の連携にはDevice Profile for Web Serviceを利用し,デバイス間の通信ではアドホック連携が可能であることを強く印象付けてくれました。

次回のTech・Edは,メインテーマに「Windows Phone 7」が来ることを期待して,レポートを終わりとさせて頂きたいと思います。

はじめに

さて,本編です。前回はControlクラスを継承したボタンコントロールクラスを作成し,グラデーションがかったボタンが作れることをご紹介致しました。今回はButtonクラスをサブクラス化したボタンコントロールの作り方をご紹介したいと思います。手間はかかりますが,Controlクラスから派生して作るよりも簡単に完成度を高めることができます。

以前,Windowsプラットフォームは「Windows メッセージ」と呼ばれるウィンドウに対する指示が飛び交っているというお話を本連載の第4回目でしました。そのWindows メッセージは,該当するコントロールのウィンドウプロシージャであるWndProcに対して送られます。ネイティブアプリケーションでは,WndProc内でメッセージに応じた処理を行いますが,.NET Compact Frameworkでは隠ぺいされており通常扱うことはしません。

そこでMSDNオンラインライブラリで公開されている「WndProcHookerクラス」を利用して,なるべく手間を掛けずにサブクラス化を実現したいと思います。今回はサンプルソースコードを用意していますので参考にしてください。

WndProcHookerクラスを利用する

WndProcHookerクラスは,.NET Compact Frameworkからは見えないWndProcが受け取った特定のメッセージに対して「フック」を掛けて,マネージコード側でコールバックを受け取る手段を提供します。

方法 : WndProcHooker クラスを使用するにあるWndProcHookerクラスの中身をコピーしましょう。新規にクラスファイルを作成しましょう(サンプルソースコードではWndProcHooker.csとしました)⁠

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace GradientionSample
{
    public class WndProcHooker
    {
      // WndProcHookerの実装
    }
}

上記のような形になっていれば問題ありません。次は,Win32クラスにWndProcHookerクラスで使用するネイティブ関数と定数の定義を追加しましょう。必要なのは,WndProcのデリゲート,WindowProcを制御するネイティブ関数,フックのキーとなるWindows メッセージ,そのコールバックの中で使用する描画用のネイティブ関数です。

  public sealed class Win32
  {
      // for WndProc.
      public delegate int WndProc(IntPtr hwnd, uint msg, uint wParam, int lParam);
      
      [DllImport("coredll.dll")]
      public extern static IntPtr SetWindowLong(
          IntPtr hwnd, int nIndex, IntPtr dwNewLong);
      public const int GWL_WNDPROC = -4;
      
      [DllImport("coredll.dll")]
      public extern static int CallWindowProc(
          IntPtr lpPrevWndFunc, IntPtr hwnd, uint msg, uint wParam, int lParam);
      
      [DllImport("coredll.dll")]
      public extern static int DefWindowProc(
          IntPtr hwnd, uint msg, uint wParam, int lParam);
      
      // Windows メッセージ
      public const uint WM_PAINT = 0x000F;
      public const uint WM_ERASEBKGND = 0x0014;
      public const uint WM_KEYDOWN = 0x0100;
      public const uint WM_KEYUP = 0x0101;
      public const uint WM_MOUSEMOVE = 0x0200;
      public const uint WM_LBUTTONDOWN = 0x0201;
      public const uint WM_LBUTTONUP = 0x0202;
      public const uint WM_NOTIFY = 0x4E;
      
      // for WM_Paint
      [DllImport("coredll.dll")]
      public extern static IntPtr GetDC(IntPtr hwnd);
      
      [DllImport("coredll.dll")]
      public extern static bool ReleaseDC(IntPtr hwnd, IntPtr hdc);
      
      [DllImport("coredll.dll")]
      public extern static IntPtr BeginPaint(IntPtr hwnd, ref PAINTSTRUCT ps);
      
      [DllImport("coredll.dll")]
      public extern static bool EndPaint(IntPtr hwnd, ref PAINTSTRUCT ps);
      
      public struct PAINTSTRUCT
      {
          private IntPtr hdc;
          public bool fErase;
          public Rectangle rcPaint;
          public bool fRestore;
          public bool fIncUpdate;
          [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
          public byte[] rgbReserved;
      }
      
      public static Point LParamToPoint(int lParam)
      {
          uint ulParam = (uint)lParam;
          return new Point(
              (int)(ulParam & 0x0000ffff),
              (int)((ulParam & 0xffff0000) >> 16));
      }
  }

以上の定義が終われば,WndProcHookerクラスを使用する準備ができました。

WndProcHookerクラスを使ってボタンコントロールを実装する

前回まで実装していたボタンコントロールは「GradientionButton」という名前を付けていました。今回は「GradientionButton2」という名前でSystem.Windows.Forms.Buttonクラスを継承したボタンコントロールを実装します。

コンストラクタでWM_PAINTのイベントを受け取ったらWM_Paint_Handlerメソッドが呼ばれるように,WndProcHookerでイベントとハンドラメソッドのマッピングを行います(下記のソースコードでは,本質的ではないDrawButtonメソッドは省略して掲載していますので,サンプルソースコードを見て頂ければと思います)⁠

  class GradientionButton2 : System.Windows.Forms.Button 
  {  
      public GradientionButton2()
      {
          // WM_PAINTをフックして,WM_Paint_Handlerメソッドを呼び出す
          WndProcHooker.HookWndProc(this,
              new WndProcHooker.WndProcCallback(this.WM_Paint_Handler),
              Win32.WM_PAINT);
      }
      
      // WndProcがWM_PAINTを受け取った際のコールバック関数
      int WM_Paint_Handler(IntPtr hwnd, uint msg, 
          uint wParam, int lParam, ref bool handled)
      {
          Win32.PAINTSTRUCT ps = new Win32.PAINTSTRUCT();
      
          Graphics gr = Graphics.FromHdc(Win32.BeginPaint(hwnd, ref ps));
      
          // 前回作成した描画メソッドの呼び出し
          DrawButton(gr, this.Capture, this.Focused);
          gr.Dispose();
          Win32.EndPaint(hwnd, ref ps);
      
          handled = true;
          return 0;
      }
  }

このGradientionButton2をフォームデザイナで,フォームに配置して実行すると以下のように表示されます。一番上が標準のButtonコントロール,真中がControlクラスを継承したボタン,一番下が今回作成したButtonコントロールをサブクラス化したボタンになります。

画像

ちなみにこの対応だけですと,アプリ起動時の最初しかグラデーション掛かったボタンが描画されません。このボタンをタップすると標準のButtonコントロールの表示となってしまいますので,マウスのダウンイベント時とリリース時にそれぞれイベントを拾ってあげる必要があります。こちらの対応に関してはサンプルソースコードを見てください。

さいごに

Controlクラスを継承して作成したグラデーションボタン,Buttonコントロールをサブクラス化して作成したグラデーションボタンの2種類のカスタムボタンの作成の仕方を触りだけですがご紹介させて頂きました。

随分長くなってしまいましたが,Windows Mobile 6.xでグラデーションのボタンを作ってみよう!は終わりです。触りだけの紹介でしたので,もっとこだわりを持って見え方を調整することで,グラフィカルなボタンを作成することが可能かと思いますので,色々とチャレンジして頂ければと思います。

以上で今回は終わりです。ありがとうございました。

著者プロフィール

和田健司(わだけんじ)

1982年10月12日生まれ。大阪で働くプログラマ。Microsoft MVP for Device Application Development(Jul 2010 - Jun 2011)。Windows Mobileに傾倒し今に至る。Windows Mobile向けのTipsを書いています。iPhoneアプリ開発を始めました。嫌いな食べ物はカレー。

URL: http://ch3cooh.jp/
Blog: http://d.hatena.ne.jp/ch3cooh393/

コメント

コメントの記入