5.1 マウス入力
5.1.1 クリックに反応する
ここからは、ウィンドウ上のコンテンツに対して、ユーザーが何らかの入力を行ったときに発生するイベントを処理する方法について説明します。Microsoft .NET では、言語レベルでイベント処理の機能が提供されているため、WPF もこれに従います。本書では、C# 言語の構文としてのデリゲートやイベントについての解説は行いません。これらは、Windows Forms アプリケーション時代から使われていた技術です。
WPF でも、基本的なイベントの概念や処理方法に変更はありません。開発者は、イベントを処理するためのイベントハンドラを用意し、監視したいコントロールが公開しているイベントに、イベントハンドラのデリゲートを渡すだけです。イベント登録手続きが適切に行われていれば、アプリケーション実行時に、ユーザーがコントロールに何らかの入力を行うと、イベントハンドラが自動的にコールバックされます。この仕組みは、これまでの .NET アプリケーションと同じです。
WPF では、コントロールも図形も、同一の UIElement クラスから派生しています。よって、こうした描画要素に共通する、マウスやキーボードなどの基本的なイベントは全て UIElement クラスで提供されています。イベントの処理方法は WPF 独自の新しいものではありません。本書では基本的なイベント処理の例を紹介するに留めます。詳細は、ドキュメントを参照してください。
最も基本的な操作である、マウスが押されたことを感知するには MouseDown イベントを利用します。
public event MouseButtonEventHandler MouseDown
MouseDown イベントには System.Windows.Input.MouseButtonEventHandler デリゲートを追加、または削除できます。このイベントに登録されているデリゲートがイベント発生時(マウスが押されたとき)に呼び出されます。
public delegate void MouseButtonEventHandler ( Object sender, MouseButtonEventArgs e )
MouseButtonEventHandler デリゲートは、sender パラメータにイベント発生元のオブジェクトを、e にイベントに関連する情報を提供するイベントオブジェクトを受け取ります。このデリゲートのパラメータも、古くから .NET で使われている設計に基づいています。
MouseButtonEventHandler デリゲートが受け取るイベントオブジェクトは、マウスのボタン入力に関連する情報を提供する System.Windows.Input.MouseButtonEventArgs クラスです。このクラスは、マウスの各種ボタンが押されているかどうかなどの情報をプロパティから提供します。
System.Object System.EventArgs System.Windows.RoutedEventArgs System.Windows.Input.InputEventArgs System.Windows.Input.MouseEventArgs System.Windows.Input.MouseButtonEventArgs
public class MouseButtonEventArgs : MouseEventArgs
イベントハンドラが、イベント発生時の情報を提供する e パラメータを利用するかどうかは開発者の問題です。イベントが発生したと言う事実だけに興味がある場合は e を使う必要はありませんし、押されたボタンなどに応じて処理結果を分岐させたい場合は MouseButtonEventArgs から情報を取得します。
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; using System.Windows.Input; class Test : Window { [STAThread] public static void Main() { Window wnd = new Test(); Application app = new Application(); app.Run(wnd); } private Ellipse ellipse; public Test() { ellipse = new Ellipse(); ellipse.Fill = Brushes.Blue; ellipse.Width = 200; ellipse.Height = 200; ellipse.MouseDown += ellipseMouseDown; Content = ellipse; } private void ellipseMouseDown(object sender, MouseButtonEventArgs e) { ellipse.Fill = Brushes.Red; } }
コード1は、アプリケーション起動時に、ウィンドウのコンテンツとして青いブラシで内部を塗りつぶす Ellipse オブジェクトを追加しています。表示された青い楕円形をマウスでクリックすると Ellipse オブジェクトの MouseDown イベントに追加されているデリゲートから ellipseMouseDown() メソッドがコールバックされ、Ellipse オブジェクトの Fill プロパティに赤いブラシを設定します。これら一連の作業は、ユーザーにとって楕円形をクリックすると色が変わるという処理になります。
5.1.2 イベント情報
押されたボタンに応じて処理を分岐させるには、イベントハンドラで受け取る MouseButtonEventArgs オブジェクトを利用します。このクラスは、 イベント発生時のボタンの状態を返すプロパティを提供しています。
どのマウスボタンの入力によってイベントが発生したかという情報は ChangedButton プロパティから取得することができます。
public MouseButton ChangedButton { get; }
ChangedButton が返すのは、イベントの引金となったマウスボタンを表す値です。この値は、System.Windows.Input.MouseButton 列挙体のいずれかのメンバです。
public enum MouseButton
MouseButton 列挙隊のメンバは、左ボタンを表す Left、中央ボタンを表す Middle、右ボタンを表す Right、そして拡張ボタンを表す XButton1 と XButton2 があります。
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; class Test : Window { [STAThread] public static void Main() { Window wnd = new Test(); Application app = new Application(); app.Run(wnd); } private TextBlock textBlock; public Test() { textBlock = new TextBlock(); textBlock.Text = "マウスボタンを押してください"; textBlock.FontSize = 30; MouseDown += mouseDown; Content = textBlock; } private void mouseDown(object sender, MouseButtonEventArgs e) { textBlock.Text = "MouseButton=" + e.ChangedButton; } }
コード2は、ウィンドウ上でマウスボタンを押すと、押されたマウスボタンに対応する MouseButton 列挙体の値を表示するプログラムです。
イベントを発生させたボタンとは無関係にイベント発生時のマウスボタンの状態を取得するために、個別のボタンの状態を保存するプロパティが用意されています。左ボタンを表す LeftButton プロパティ、右ボタンを表す RightButton プロパティ、中央ボタンを表す MiddleButton プロパティから、それぞれのボタンの状態を取得することができます。
public MouseButtonState LeftButton { get; }
public MouseButtonState RightButton { get; }
public MouseButtonState MiddleButton { get; }
これらのプロパティが返す値は System.Windows.Input.MouseButtonState 列挙体のメンバのいずれかです。
public enum MouseButtonState
この列挙体には、ボタンが押されている状態を表す Pressed メンバと、離されている状態を表す Released メンバの 2 つが宣言されています。
イベントハンドラが受け取った MouseButtonEventArgs オブジェクトから、調べたいボタンの MouseButtonState 列挙体の値を取得し、Pressed メンバに一致すればボタンが押されていることを確認できます。
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; using System.Windows.Input; class Test : Window { [STAThread] public static void Main() { Window wnd = new Test(); Application app = new Application(); app.Run(wnd); } private Ellipse ellipse; public Test() { ellipse = new Ellipse(); ellipse.Stroke = Brushes.Black; ellipse.Fill = Brushes.White; ellipse.Width = 200; ellipse.Height = 200; ellipse.MouseDown += ellipseMouseDown; Content = ellipse; } private void ellipseMouseDown(object sender, MouseButtonEventArgs e) { if (e.LeftButton == MouseButtonState.Pressed) ellipse.Fill = Brushes.Red; else if (e.RightButton == MouseButtonState.Pressed) ellipse.Fill = Brushes.Blue; } }
コード3は、アプリケーション起動時の初期状態で、内部を白色のブラシで塗りつぶす Ellipse オブジェクトを表示します。この楕円形をマウスの左ボタン、または右ボタンでクリックすると、ブラシを変更して色が変化するように仕組んでいます。
ellipseMouseDown() メソッドでは、e パラメータから左ボタンや右ボタンが押されているかどうかを調べています。もし、イベント発生時に左ボタンが押されている場合は楕円形を赤色に塗りつぶし、右ボタンが押されていれば青色に塗りつぶすように、プログラムを if 文で分岐させています。
マウスイベントでは、マウスボタンの状態の他に、イベントが発生したときのカーソルの座標も重要な情報となります。カーソルの座標は GetPosition() メソッドから取得することができます。
public Point GetPosition (IInputElement relativeTo)
このメソッドの relativeTo パラメータには、カーソルの座標を受ける IInputElement インターフェイスを実装しているオブジェクトを指定しなければなりません。FrameworkElement クラスが IInputElement インターフェイスを実装しているので GetPosition() メソッドには、イベントが発生したコントロールを渡すのが一般的でしょう。
このメソッドが返す Point オブジェクトにマウスカーソルの座標が格納されています。この座標は、relativeTo で指定したコントロールの相対座標となります。
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; using System.Windows.Input; class Test : Window { [STAThread] public static void Main() { Window wnd = new Test(); Application app = new Application(); app.Run(wnd); } private Ellipse ellipse; public Test() { ellipse = new Ellipse(); ellipse.Fill = Brushes.Black; ellipse.Width = 100; ellipse.Height = 100; Canvas canvas = new Canvas(); canvas.Children.Add(ellipse); Content = canvas; MouseDown += thisMouseDown; } private void thisMouseDown(object sender, MouseButtonEventArgs e) { Point pt = e.GetPosition(this); Canvas.SetLeft(ellipse, pt.X - (ellipse.Width / 2)); Canvas.SetTop(ellipse, pt.Y - (ellipse.Height / 2)); } }
コード4は、マウスボタンを押すと、Canvas 上の楕円形が移動するというプログラムです。このプログラムでは MouseDown イベントが発生すると、イベントハンドラで Ellipse オブジェクトの座標を、イベント発生時のカーソルの座標を参考に再設定しています。
詳細は省略しますが、MouseDown イベントのような形で、この他にも多くのマウスイベントが用意されています。
イベント | 発生条件 |
---|---|
MouseDown | マウスボタンが要素上で押された。 |
MouseUp | マウスボタンが要素上で離された。 |
MouseLeftButtonDown | マウスの左ボタンが要素上で押された。 |
MouseLeftButtonUp | マウスの左ボタンが要素上で離された。 |
MouseRightButtonDown | マウスの右ボタンが要素上で押された。 |
MouseRightButtonUp | マウスの右ボタンが要素上で離された。 |
MouseWheel | マウスホイールが要素上で回転した。 |
MouseEnter | マウスカーソルが要素の領域上に侵入した。 |
MouseMove | マウスカーソルが要素の領域上で移動した。 |
MouseLeave | マウスカーソルが要素の領域の外に出た。 |
表1は、UIElement クラスで提供されている主なマウスイベントです。これらのイベントは発生条件やデリゲート型が異なりますが、基本的な利用方法は同じです。