*
MSDN*
Bing による検索結果
|MSDN ライブラリ|デベロッパー センター|ダウンロード情報|開発ツール製品|コミュニティ|ご意見・ご要望|サイトマップ
MSDN Magazine  
   MSDN Home >  MSDN マガジン >  2005 年 9 月
魅力的にする

ありきたりの Windows フォーム アプリケーションを活気付ける



この記事で取り上げる話題:
  • 魅力的なウィンドウの設計
  • "トースト" ポップアップの作成
  • フォームの配色と透明度の追加
  • 透過と半透過の作用
この記事で使用する技術:
.NET、Windows フォーム


サンプルコードのダウンロード:
WindowsForms.exe (英語) (864KB)

目次
補足記事


Microsoft .NET Framework による Windows ベース アプリケーションの作成は、とても簡単です。フォームを作成してコントロールを追加し、ビジネス ロジックと結合すれば終了です。しかし、こうして作成されたアプリケーションは、ユーザーが本当に求めているイントラクションを提供できていないのが現状です。たとえば、重大な外部イベントが発生した際、通常はユーザーに通知しません。ましてウィンドウは、すべて同じ外見で、どれを見ても鈍い灰色のフォーム、同じ標準コントロールで魅力に欠けます。

.NET Framework および GDI+ を使用すると、作成中のアプリケーションにスタイル要素を簡単に追加できます。透明度の変更、不規則な形のウィドウ、通知アイコン、トースト ポップアップ、配色の変更、その他、多数のデザイン要素を使用できます。うまくデザインすれば、ユーザーのアプリケーション操作感を充実させることができます。


アプリケーションをお洒落に

洒落たアプリケーションに仕上げるために適用できる簡単なテクニックは、色々あります。たとえば、重要なイベントをユーザーに警告する通知ウィンドウは目立つようにし、一方、優先度の低い出来事をユーザーに知らせる場合は、控えめな方法で通知するようにします。多くのアプリケーションが、このテクニックを効果的に応用しています。たとえば、MSN Messenger が、友人がログインしていることを通知したり、コンタクトを取ろうとしている友人がいることを知らせるためにトレイ上に表示するポップアップは魅力的ですし、Outlook 2003 は、新着メールをデスクトップに通知します(このような通知は、到着時の処理として、削除、フラグ設定、読む、のいずれかをユーザーが選択できます)。ユーザーが対話するフォームやウィンドウにアピール性を持たせると、ユーザーのアプリケーション使用感を充実させることができます。たとえば、Windows Media Player では、好みのスキンを選択できるし、ウィンドウの形も標準の長方形の域を超えています。当然、このようなテクニックのすべてを、あらゆるアプリケーションに適用することは良策ではありませんが、いくつかのテクニックを厳選して適用すれば、ユーザーを満足させるアプリケーションを作成できます。

この記事では、単純なイベント モニター アプリケーションを変更しながら、デザイン変更テクニックを使用するタイミングと方法を説明します。最初のアプリケーションは、指定した都市の最新気象データを表示します (図 1 を参照)。この典型的な .NET ベースのデスクトップ アプリケーションは、Web サービスでデータを取得し、結果を Windows 標準コントロールを使用してフォームに表示します。www.xmethods.net (英語) では、私が使用した Web サービスを含め、多くの Web サービスが見つけられるでしょう。

図 1 標準のアプリケーション ウィンドウ
図 1 標準のアプリケーション ウィンドウ

このアプリケーションは、特にフレンドリーなものではありません。画面全体が気象情報に占領されるうえ、定期的に Update ボタンを押して更新しなければなりません。この記事では、この後、ユーザーの使用感を向上するアプリケーションに作り変える方法を説明します。最終的には、自動更新する気象警告センターに仕上げます。特定の都市をモニターし、天候に重大な変化が起きた時に通知します。味気ないグレーのアプリケーションの鋳型を打ち破ります。さらにアプリケーションを変更すれば、タスクバーの通知アイコンとして実行し、イベント発生時に任意のポップアップ情報として表示したり、アプリケーション自体を起動して、好きなウィンドウの形、バックグラウンドに情報を表示することも可能です。

Back to top

メイン ウィンドウの依存関係の解除

最初の作業は、メイン フォームへの依存を解除して、メイン フォーム起動時に、代わりに通知アイコンを作成するアプリケーションを起動するように変更します。起動コードは相当な分量があるので、最善策は、アプリケーション レベルのタスクを扱う新しいクラスを作成することです。アプリケーションのコピーをいくつもチェックし、通知アイコンの作成、メニューやハンドラの追加、タイマーの起動、メッセージ ループの開始、いくつかのセッション イベントのハンドリングをおこなうことになります。

通知アイコンとして実行するアプリケーションを作成するには、こうした小さな作業をすべて実行することが重要です。もし、適切に片付けなければ、タスクバーの通知領域に、いくつもの通知アイコンのコピーが現れる結果に簡単に陥ってしまいます。こうなってしまうと、このアプリケーションの使用は困難を来たします。ユーザーは、どの通知アイコンが、どのセッションを発したのかを突き止めるために、始終混乱してしまいます。

この問題を緩和するには、まず第一に、アプリケーションの多重起動をさせないことです。アプリケーションが実行中であることを示すグローバル ミューテックス作成することで可能です。 (この問題の詳細は、MSDN Magazine のコラム 「.NET Matters」 を参照してください)。最初のインスタンスがミューテックスを取得し、アプリケーション起動中これを所有します。次のコピーがミューテックスを取得しようと試みると、失敗して終了します。下にコードを示します。

Public Shared Sub Main()
    Dim appSingleton As New System.Threading.Mutex(False, _
        "SingleInstance WeatherAlert")
    If appSingleton.WaitOne(0, False) Then Application.Run()
    appSingleton.Close()
End Sub

次に、現在作成中のアプリケーションで、Window XP のテーマを有効にします。 EnableVisualStyles のことは知っていると思いますが、 .NET Framework 1.x を使用している場合は、下位互換性を有効にするために、若干のコードを追加する必要があります (.NET Framework 2.0 を使用する場合は、コードを追加する必要はありません)。古い OS を使用している場合は、EnableVisualStyles を呼び出すと、uxtheme.dll が無いために、プログラムは終了します。新しい OS にテーマを適用する前にテストが必要です。以下にコードを示します。

Private Shared Sub InitThemes()
  If (((Environment.OSVersion.Platform = PlatformID.Win32NT) _
    AndAlso (Environment.OSVersion.Version.Major >= 5)) _
    AndAlso (Environment.OSVersion.Version.Minor > 0)) Then
      If OSFeature.Feature.IsPresent(OSFeature.Themes) Then
        Application.EnableVisualStyles()
      End If
      Application.DoEvents()
    End If
End Sub

メイン アプリケーション クラスも、通知アイコンを作成し、メイン メッセージ ループを実行します。メイン ウィンドウ無しでアプリケーションを実行することと、メイン ウィンドウ有りで実行することの違いは、ほとんどありません。変更しなければならない事は 2 つだけです。メイン フォーム無しでメッセージ ループを開始するために、Application.Run(FormName) 呼び出しを Application.Run() に変更します。ユーザーがメイン ウィンドウをまったく作成しない場合は、不可視のメイン ウィンドウを作成する必要はありません 。次に、SessionEnded イベントの取り扱いを変更します。アプリケーション実行中に、ユーザーが Windows からログオフした場合、Windows は、SessionEnded イベントを起動して、アプリケーションを終了するように要求します。このイベントに回答が無いと、Windows はアプリケーションがクラッシュしたものと判断し、ユーザーに、アプリケーションが反応しないことを通知して、終了させるように要求します。これを修正するために、イベントに対応してアプリケーションを終了するようにします。次のようなコードで、ハンドラをメイン アプリケーションに組み込みます。

AddHandler Microsoft.Win32.SystemEvents.SessionEnded, _
    New Microsoft.Win32.SessionEndedEventHandler(AddressOf _
    ApplicationMain.SystemEvents_SessionEnded)
ハンドラの中を、クリーンにして最適化します。
Private Shared Sub SystemEvents_SessionEnded(ByVal sender As Object, _
    ByVal e As Microsoft.Win32.SessionEndedEventArgs)
    If (Not _mainWindow Is Nothing) Then _mainWindow.Close()
    _icon.Visible = False
    Application.Exit()
End Sub

終了コードは、標準の Windows フォーム アプリケーションとは異なる項目が数点あります。Close する前に、メイン ウィンドウが作成されたかどうかを確認する必要があります。恐らくユーザーは、メイン ウィンドウを開こうとさえしていないでしょう。次に、通知アイコンを隠さなければなりません。トレイ アイコンが姿を消し、ゴーストのトレイ アイコンが残り、これを起動しようとすると消えてなくなるという動作をするプログラムを見たことがあるでしょう。開発者がタスクバー内の消去を忘れてしまったことが原因です。通知アイコンは、プログラム終了前に隠しましょう。通知アイコンに対応する Close メソッドはありません。アイコンを隠せば、自ずと消去となります。

Back to top

ユーザーへの通知

次は、アプリケーションがアイコンとして実行された時に、ユーザーに示すフィードバックを用意します。最高のポップアップ ウィンドウを作成しましょう。私は、標準のバルーン型の通知が好きではありません。Outlook のメッセージ到着の通知や、MSN Messenger が友人がサインインしたことを知らせる通知などのように、ちょっとしたデザインがされているものが好きです。また、ユーザーの通常の作業を妨げることなく通知する方法が良いと思います。

正しく構成された Outlook 2003 でメールを受信すると、メッセージの送信者と件名を示す小さなウィンドウが、画面の右端に現れます。このウィンドウから、受信したメッセージを読むか、直ぐにメッセージを削除するか、フォローアップ フラグを設定するようにクリックで指示できます。忙しい時に、急を要さないメッセージが到着した場合は、ポップアップを無視していれば、表示が消え、未読メッセージとして残ります。

同様のウィンドウを気象警告アプリケーション用に作成すれば、ユーザーは、アップデートされた気象情報を受信しやすくなります。通知ウィンドウ自体には、要約のみ表示し、ユーザーが無視する場合は、消えるようにすると良いでしょう。ユーザーに、消すためのアクションを強要するような通知フォームは、作成しないようにします。ユーザーが机の前に居ないか、メッセージが現在のタスクを中断して構わない程度の重要性しか持たない場合には、通知は消えるようにします。

図 2 通知ボックス
図 2 通知ボックス

ウィンドウは、デスクトップの右下、通知アイコンの真上に配置します。トースト ウィンドウは、現れてから数秒間表示して消えると良いでしょう。簡単に使用できるように、ユーザーがマウスをウィンドウ上に移動させると瞬時に不透明になり、ユーザーがウィンドウから離れるまで消えないようにします。ユーザーがメイン アプリケーションを開くには、トースト アイコンをクリックするだけで、アプリケーションのメイン ウィンドウを表示します。最後に、少しデザインを加えましょう。グラデーション ブラシを使用して背景を描き、通常のウィンドウの縁を隠します (図 2 を参照)。GDI+ を使用すると簡単です。

Back to top

GDI+ の使用方法

透過的で非長方形のウィンドウは、数ステップで簡単に作成できます。始めに、デザイナの FormBorderStyle を None に変更します。これで、普通の非クライアント領域のすべてのオブジェクトが、トースト ウィンドウから無くなります。閉じるボタン、システム メニュー、サイズ変更ハンドルはありません。"Show In Taskbar" の設定を無効にします。トースト ウィンドウは、タスクバーに表示したくありません。

透過性については、クロマキーという方法で完成させます。クロマキー処理したイメージは、透明にする色を 1 色だけ指定します。ウィンドウが描画される時、指定された色と一致するピクセルは描画されません。通常、アプリケーションで使用される可能性の低い色を選択することが重要です。白、黒、グレーは頻繁に使用される色なので、これらは選択すべきではありません。Visual Studio .NET では、Windows フォームのプロパティの TransparencyKey プロパティで、Transparent Color を設定します。クロマキーの詳細については、サイド バーの "クロマキー、アルファ ブレンド、透過性" を参照してください。

透過性に関する設定を終了したら、背景を描画するコードを追加する必要があります。丸めた長方形の描画機能を GDI+ で実装する場合は、GraphicsPath が使用できます。実際、GraphicsPath を使用すれば、様々な不規則な形を作成できます。図 3 のコードは、rounded rectangle path を作成するために今回使用した方法を示しています。

この背景には、新しい GDI+ の機能の 1 つ、グラデーション ブラシを使用しています。狙い通りのバックグラウンドの効果を作成するために、直線用のグラデーション ブラシを使用しました。始めに、バックグラウンドの長方形全体を、透き通ったライム グリーンで塗りつぶし、次に、内側の丸めた長方形全体を、直線用グラデーション ブラシを使用して、スチール ブルーからライト ブルーへ、徐々に薄くしました。この作業は、すべて OnPaintBackground メソッドをオーバーライドする方法で行いました。イベント ハンドラを適切なイベントと結び付けるより、オーバーライドを適用する方が効率的です。

描画コードを終了するために、テキストを描画する paint ハンドラを追加しなければなりません。これは、トースト ウィンドウに渡されたコンストラクタ中のメッセージを描画します。次に、システム定義されたリンクの色およびアクティブ リンクと矛盾しないフォントを設定します。ユーザーがトースト ウィンドウに入ったら、ウィンドウのフォントをアンダーライン表示に変更します。ユーザーがウィンドウを離れたら、フォントを元通りに戻します。この手法は、ユーザーに、トースト ウィンドウの文字はリンクだという印象を与えます。

Back to top

フェード イン、フェード アウト

次の作業は、トースト ウィンドウの不透明性をアップデートするためのタイマーとハンドラの追加です。デザイナで、タイマーを追加して、トースト ウィンドウの Opacity の初期値を 0 % に設定します。タイマー イベントが解放されると、不透明度が増加します (サンプル コードでは、0.05 秒ごとに増加します)。Opacity が 1 に到達したら、3 秒後にタイマーを解放するようにリセットします。こうして、ユーザーがトースト ウィンドウを見ることのできる時間を確保します。次に、タイマーのインターバルを短くリセットし、タイマーが解放される度に、Opacity 値を下げます。Opacity が 0 に戻ったら、ウィンドウを閉じます。

ユーザーがマウスをトースト ウィンドウに移動した時に発生する、フェード インおよびフェード アウトのプロセスを停止するためのハンドラを追加する必要があります。そして勿論、ユーザーがウィンドウから去った時に、フェード アウト プロセスを再開します。ここで、注意しなければならない事が 1 つだけあります。閉じるボタン (図 2 を参照) は、子ウィンドウです。メイン ウィンドウは、ユーザーがマウスを閉じるボタンの上に移動した時に、MouseLeave メッセージを受け取ります。

トースト ウィンドウのための mouse enter メソッドと mouse leave メソッドの他に、トースト ウィンドウ中にある、すべての子ウィンドウ用のイベント ハンドラを追加する必要があります。enter / leave イベントを受け取っている間に、ユーザーがマウスを閉じるボタンと親ウィンドウの間を行き来させた場合は、一方のウィンドウが MouseEnter イベントを受け取る前には、もう一方からの MouseLeave メッセージを決して受け取りません。これが何を意味するかというと、一方のウィンドウから別のウィンドウに移動したという間違ったステートを受け取ることは無いということです。トースト ウィンドウは、ユーザーが操作している間は、決して消えません。

トースト ウィンドウの実装を終了する前に、複数のアップデートを受け取った時の行動を定義する必要があります。このサンプル コードでは、簡単な方法を採用しています。トースト ウィンドウが表示されている間に、次の通知が発生した場合は、単純に無視します。市販のアプリケーションは、別のアプローチを取っています。Outlook 2003 は、メールごとにトースト ウィンドウのキューを 1 つずつ作成します。MSN Messenger は、デスクトップの最前面に到達するまで、トースト ウィンドウをスタックします。このサンプルは、時間を費やす価値がある程の面白みのある通知を生成しません。

Back to top

アプリケーションのスキン作成

今度は、メイン ウィンドウに少しデザインを加えましょう (図 4 を参照)。効果を演出するために、背景のイメージを作成する必要があります。透明にしたい任意の場所は、TransparentColor で指定した色で描画されなければなりません。サンプルでは、背景はライム グリーンです。背景のイメージを新しいビットマップとして設定し、FormBorderStyle を None に設定します。もうすぐ、作業終了です。ここで、グラフィック カードに関する問題があります。カードの中には、ビットマップの色の深度がモニターの色の深度と調和しない場合に、透過性の機能を妨げるものがあります (詳細は、サポート技術情報の文書番号 822495 BUG: モニタのカラー奥行きが 24 - ビットより、大きい値に設定される場合、 Windows フォームに TransparencyKey プロパティが有効ではありません。 を参照してください)。これを修正するには、背景のビットマップを透過にする必要があります。次に示すコードでは、OnLoad のオーバーライドがこれをします。

Protected Overrides Sub OnLoad(ByVal e As EventArgs)
    Dim bitmapBG As Bitmap = _CType
(BackgroundImage,Bitmap)
    bitmapBG.MakeTransparent(bitmapBG.GetPixel(0, 0))
    TransparencyKey = bitmapBG.GetPixel(0, 0)
    MyBase.OnLoad(e)
End Sub
イメージをアップデートしたら、ピクセル値の変更を一致させるために、Transparency key もアップデートする必要があります。

図 4 メイン ウィンドウへのスタイル追加
図 4 メイン ウィンドウへのスタイル追加

次は、コンソールを、背景の前面で見栄えのする透過なコンソールに変更します。私は、背景のイメージに対して目立つように、黄色いフォントを選びました。背景の色を変更するには、デザイナを使用するか、コードで、System.Drawing.Color.Transparent を設定します。これで、背景のイメージが、コントロールから見えるようになります(図 5 を参照)。

図 5 バックグラウンドのイメージが透けて見える
図 5 バックグラウンドのイメージが透けて見える

最後に、メイン ウィンドウを画面上の任意の場所へ移動できる機能を追加すると、ユーザーの操作性が向上します。タイトル バーはもはや存在しないので、見えているフォーム上のどこかでマウスの左ボタンを押し、ウィンドウを好きな場所へドラッグすれば、移動できます。ユーザーがドラッグした時にウィンドウを移動するのは、MouseMove メソッドです。

Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
    If _isMoving Then
        Location = New Point(Location.X + e.X - XOffset, 
            Location.Y + e.Y - YOffset)
    End If
    MyBase.OnMouseMove(e)
End Sub
これは非常にうまく機能しますが、気象情報を表示するために作成した子ウィンドウのいずれかでマウスをクリックした場合には機能しません。この場合にも機能させるために、子ウィンドウ上でマウスのボタンをクリックした時に移動処理を開始する mouse down ハンドラを作成する必要があります。ただし、リンク ボタンと閉じるボタンのデフォルトの行動は必要なので、すべての子ウィンドウ上で機能させるべきではありません。 以下のコードに示すように、同じメソッドで、この 2 つを除くすべての子コントロールのあらゆる MouseDown イベントをハンドルできます。
Private Sub Child_MouseDown(ByVal sender As Object, _
    ByVal e As System.Windows.Forms.MouseEventArgs) Handles _
        labelAirPressure.MouseDown, labelDewPoint.MouseDown, _
        labelHumidity.MouseDown, labelLocation.MouseDown, _
        labelSkyConditions.MouseDown, labelTemperature.MouseDown, _
        labelVisibility.MouseDown, labelWind.MouseDown
    If (e.Button = MouseButtons.Left) Then
       _isMoving = True
       XOffset = e.X
       YOffset = e.Y
    End If
End Sub
閉じるボタンと、最新の気象情報を獲得するためのリンク ボタンを追加すれば、終了です。

Back to top

まとめ

標準とは異なる対話方法を取るアプリケーションを作成するときは、目立つようにしましょう。ただし、やりすぎは禁物です。ユーザーは標準の外観を見慣れていますので、それを変更するなら最善策であるときにおこないましょう。システム トレイの場所を取るアプリケーションが非常に多いですが、それが本当にユーザーと対話するための最善策でない限り、標準の方法を変更しないことです。アプリケーションの存在をアピールする別の方法を考えましょう。

Back to top


Bill Wagner は、SRT Solutions 社の共同創立者の一人であり、マイクロソフト社ミシガン地域の管理を担当しています。著書に Effective C# (Addison-Wesley, 2004) があります。連絡先は wwagner@srtsolutions.com です (英語)。彼のブログは www.srtsolutions.com/public/blog/20574 (英語) です。

 この記事は、 MSDN マガジン - 2005 年 9 月号からの翻訳です。 .
Back to topBack to top QJ: 050905

Microsoft