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

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

Windows Phone Developer Tools Betaの公開

はじめの前にWindow Phone 7に関する新情報です。RC版のリリースが目前の7月12日にWindows Phone Developer ToolsのBeta版が公開されました。CTP(Community Technology Preview)版からBeta版への進化で、アプリケーションの構成も多少変更されており、今までCTP版で動いていたサンプルアプリケーションが動かなくなっている可能性があります。

「Windows Phone Developer Tools Beta」は、こちらからダウンロードできます。

  • Visual Studio 2010 Express for Windows Phone Beta
  • Windows Phone Emulator Beta
  • Silverlight for Windows Phone Beta
  • Microsoft Expression Blend for Windows Phone Beta
  • XNA Game Studio 4.0 Beta

Developer Toolsに同梱されているソフトウェアも当然ながらすべてBeta版にバージョンアップされています。心配していたExoression BlendもどうやらWindows Phone向けに機能制限をして、今後も無料で配布されるようです。Windows Phone向けのVisual Studio 2010 Expressも含まれていますので、完全にお金をかけずにWindows Phone 7アプリケーションの開発ができますね。

同時に今のWindows Mobileで言うところのActive Sync/Device Centerに代わる、Zune SoftwareのWindows Phone 7に対応したTechnical Preview版が一部に向けてリリースされています。あとは実機さえ届けばすぐにWindows Phone 7端末にて転送してテストすることができます。着々とWindows Phone 7の開発環境が整ってきています。

Windows Phone 7 開発者のサイトを開くと、大きく「Dream it. Build it.」のコピーが書かれており、⁠英語が不得意ですので訳を間違っていたら恥ずかしいのですが)⁠夢を見ろ。それをビルドしろ。」が、Beta版のリリース時から「Stop dreaming. Start building.」に代わっており、⁠夢見るのを止め、ビルドを始めろ。」と一つの転機であることを示唆しています。

まだ日本ではどのキャリアから発売されるか、そもそも日本でWindows Phone 7端末が出るのか判っておりません。Windows Mobile 6.5.3端末が発売され静電容量式の端末を使いつつ、本国からWindows Phone 7の情報が流れてくるのを首を長くして待っていましょう。

はじめに

前回は、任意の図形でグラデーションの描画を行いました。.NET Compact FrameworkのマネージコードからGradientFill関数を使い描画したグラデーションイメージの上に、マスクイメージを描画していました。今回はこの描画メソッドを利用して、グラデーションボタンのコントロールを作ってみましょう。

実際にコードを提示する前にボタンの状態について考えてみましょう。Windows Mobileのボタンには以下の4つの状態があります。

  • 通常の状態
  • フォーカスが当っている状態
  • ボタンが押されている状態
  • ボタンが無効(Disable)になっている状態

今回は通常の状態のボタンを表示させるまでを行います。手を加えないといけないソースコードが多くなってきましたので、こちらからサンプルプロジェクトをダウンロードして頂きまして、実行しながら以降の解説を読んで頂ければ幸いです。

グラデーションボタンコントロールを作る

名前はそのまま「GradientionButton」としましょう。フォームデザイナを使って表示位置を操作したいので、Controlクラスを継承してGradientionButtonクラスを作成します。独自描画を行う際に使用するOnPaintメソッドとOnPaintBackgroundメソッドをあらかじめオーバーライドしておきましょう。

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace GradientionSample
{
    public class GradientionButton : Control
    {
        private void DrawButton(Graphics g, bool pressed, bool focused)
        {
        }
        
        protected override void OnPaint(PaintEventArgs e)
        {
            // とりあえず通常の状態のボタンを表示する
            bool pressed = false;
            bool focused = false;

            DrawButton(e.Graphics, pressed, focused);
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
        }
    }
}

現在「ボタンがユーザーによって押されているか?」⁠コントロールにフォーカスが当たっているか?」を引数に取るDrawButtonメソッドをOnPaintメソッドからコールしています。このDrawButtonメソッドに描画用の処理を実装していきます。

角丸矩形を描画するための準備

角丸の矩形を表示するには、ネイティブのRoundRect関数を使用します。Win32.csにP/Invokeの定義を追加しましょう。

RoundRect関数は設定されたPenオブジェクトとSolidBrushオブジェクトにて描画を行いますので、描画オブジェクトであるCreateSolidBrush関数とCreatePen関数、デバイスコンテキストに描画オブジェクトを設定するSelectObject関数とDeleteObject関数も合わせて定義しておきます。

namespace GradientionSample
{
    public sealed class Win32
    {
        // ~ 省略 ~

        // 角丸の矩形を描画するのに使用
        [DllImport("coredll.dll")]
        public static extern bool RoundRect(IntPtr hdc, int nLeftRect, int nTopRect,
        int nRightRect, int nBottomRect, int nWidth, int nHeight);
        
        [DllImport("coredll.dll")]
        public static extern IntPtr CreateSolidBrush(uint crColor);
        
        [DllImport("coredll.dll")]
        public static extern IntPtr CreatePen(int fnPenStyle, int nWidth, uint crColor);
        
        [DllImport("coredll.dll")]
        public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
        
        [DllImport("coredll.dll")]
        public static extern bool DeleteObject(IntPtr hObject);
        
        public static uint RGB(Color color)
        {
            return 0x00000000 | ((uint)(color.B) << 16) | ((uint)(color.G) << 8) | (uint)(color.R);
        }

    }
}

これでマネージコードからネイティブ関数を使うためのP/Invokeの定義は終わりです。次にこれらの関数を呼び出してグラデーションボタンを描画するGraphicsExtensionクラスに手を入れていきましょう。

角丸グラデーションボタンを描画するための準備

前回作成したGraphicsExtensionクラスに、角丸矩形を描画するFillRoundRectメソッドと角丸グラデーションボタンを描画するDrawGradientRoundRectButtonメソッドを用意します。先にFillRoundRectメソッドを実装しましょう。

Graphicsオブジェクトが保持しているデバイスコンテキストのハンドルを取り出し、引数に渡された塗りつぶし色と境界線の色で作った描画オブジェクトを設定しRoundRect関数を呼び出します。

namespace GradientionSample
{
    public class GraphicsExtension
    {
        // ~ 省略 ~

        public static void FillRoundRect(Graphics g,
            Rectangle rc, Color fillColor, Color borderColor, int borderWidth)
        {
            IntPtr brush = IntPtr.Zero;
            IntPtr oldBrush = IntPtr.Zero;
            IntPtr pen = IntPtr.Zero;
            IntPtr oldPen = IntPtr.Zero;

            IntPtr hdc = g.GetHdc();

            brush = Win32.CreateSolidBrush(Win32.RGB(fillColor));
            oldBrush = Win32.SelectObject(hdc, brush);

            if (borderColor == Color.Empty)
            {
                pen = Win32.CreatePen(0, 1, Win32.RGB(borderColor));
                oldPen = Win32.SelectObject(hdc, pen);
            }

            Win32.RoundRect(hdc, rc.Left, rc.Top, rc.Right, rc.Bottom, 20, 20);

            if (borderColor == Color.Empty)
            {
                Win32.SelectObject(hdc, oldPen);
                Win32.DeleteObject(pen);
            }
            Win32.SelectObject(hdc, oldBrush);
            Win32.DeleteObject(brush); 
            
            g.ReleaseHdc(hdc);
        }

外部から呼び出し可能な形でDrawGradientRoundRectButtonメソッドを実装します。前回グラデーションイメージを作成して任意の形でクリッピングする処理を共通化していますので、ここでは角丸矩形のマスクイメージを作成する_DrawGradientRoundRectButtonメソッドをdelegateに設定している所に注目してください。

        public static void DrawGradientRoundRectButton(
            Graphics g, Rectangle rc,
            Color startColor, Color endColor, Color borderColor,
            FillDirection gradientType)
        {
            InnerDrawGradient(g, rc, startColor,
                endColor, borderColor, gradientType,
                new InnderDrawFunction(_DrawGradientRoundRectButton));
        }

_DrawGradientRoundRectButtonメソッドでは、角丸矩形のマスクイメージを描画しています。透過させる色で背景を塗りつぶし、その上に角丸矩形を描画しています。

        private static void _DrawGradientRoundRectButton(Graphics g,
            Rectangle rc, Color fillColor, Color borderColor)
        {
            // 背景は透過色でクリアしておく
            g.Clear(KeyColor);
            
            // 角丸矩形を描画する
            FillRoundRect(g, rc, fillColor, borderColor, 2);
        }
    }
}

今回のボタンの見た目に角丸でグラデーションが掛かっているだけです。_DrawGradientRoundRectButtonメソッドに光沢を表示させるような処理を入れる等、少し手を入れると印象の変わったボタンになると思いますので色々と変更してみてください。

角丸のグラデーションボタンを描画する

さてGradientionButtonクラスに戻って、角丸のグラデーションボタンを描画する処理を入れましょう。DrawButtonメソッドの中で今回実装した処理を呼び出しています。

namespace GradientionSample
{
    public class GradientionButton : Control
    {
        private void DrawButton(Graphics g, bool pressed, bool focused)
        {
          // ボタンの背景を描画
          Pen backLinePen;
          backLinePen = new Pen(Color.Black);
          
          // DrawRectangleメソッドで線を描画するが
          // 線の太さを考慮して幅と高さから引く
          Rectangle lineRect = new Rectangle();
          lineRect.X = ClientRectangle.X;
          lineRect.Y = ClientRectangle.Y;
          lineRect.Width = ClientRectangle.Width - (int)backLinePen.Width;
          lineRect.Height = ClientRectangle.Height - (int)backLinePen.Width;

          g.FillRectangle(new SolidBrush(Color.DimGray), ClientRectangle);
          g.DrawRectangle(backLinePen, lineRect);

          // ボタンの表示領域
          Rectangle btnRect = ClientRectangle;
          btnRect.X += 2;
          btnRect.Y += 2;
          btnRect.Width -= 4;
          btnRect.Height -= 4;

          Color stColor, edColor;
          stColor = Color.Red;
          edColor = Color.Black;
          
          // 角丸グラデーションボタンの描画
          GraphicsExtension.DrawGradientRoundRectButton(
              g, btnRect, stColor, edColor, Color.Black, FillDirection.TopToBottom);

          // ボタンに表示するテキストの表示(テキストは中央に表示)
          StringFormat sf = new StringFormat();
          sf.LineAlignment = StringAlignment.Center;
          sf.Alignment = StringAlignment.Center;
          g.DrawString(Text, Font, new SolidBrush(Color.White), btnRect, sf);
        }

        // ~ 省略 ~
    }
}

標準のボタンと並べてGradientionButtonをフォーム上に配置してみました。デバッグ実行した様子です。

画像

さいごに

グラデーションの掛かったボタンを作ることができました。ただ、まだタップした時のボタンが押されたようなアクションや、十字キーによるフォーカスがあたった表示ができていません。

次回は、ユーザー操作によるボタンのアクションについて実装していきましょう。

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

おすすめ記事

記事・ニュース一覧