![]() |
![]() |
XMouse.h
XMouse.m
XMouse.h
XMouse.m
2009/07/22
2009/08/04 追加
ここでは次のような読者を想定している。
なお XSlider から "A Simple Sample ..." が始まっているので、Xcode の起動の仕方が分からなければ XSlider から読んで欲しい。
ウインドウの中のボックス領域でマウス操作が発生した時のマウスイベントを捉える。
マウスイベントとしてはいろいろあるが(mouseDown, mouseUp, mouseDragged など)最初に mouseDown から始める。
マウスをクリックしたときの座標をテキストフィールドに書き出す。(下図)

新規プロジェクトで Cocoa Application を選び、プロジェクト名を XMoude とする。新規ファイルで NSView subclass を選び、ファイル名を XMouse.m とする。この時 XMouse.m の他に XMouse.h も生成される。
XMouse.h#import <Cocoa/Cocoa.h>
//#import <stdio.h>
@interface XMouse : NSView
{
IBOutlet NSTextField *messageTextField;
IBOutlet NSBox *box;
}
- (void)mouseDown:(NSEvent *)event; //Kenar
@end
この中のコメントアウトされている行
//#import <stdio.h>
はデバッグで使われていた行である。
マウスをクリックする領域(box)、クリックした座標を表示するテキストフィールド(messageTextField)およびマウスクリック(mouseDownを捉えるメソッドが宣言されている。
XMouse.m#import "XMouse.h"
@implementation XMouse
- (void)mouseDown:(NSEvent *)event //Kenar
{
// mouse-down event comes here.
NSString *s;
NSPoint p = [event locationInWindow];
NSRect r;
s = [NSString stringWithFormat:@"(%f,%f)", p.x,p.y];
//NSRunAlertPanel(@"Message", (NSString *)s, NULL, NULL, NULL);
//if(!box) NSRunAlertPanel(@"Warning", @"box nil", NULL, NULL, NULL);
r = [box frame];// frame is a generic method for NSView class.
//printf("%f,%f,%f,%f\n",r.origin.x,r.origin.y,r.size.width,r.size.height);
//printf("%f,%f,%f,%f\n",NSMinX(r),NSMinY(r),NSWidth(r),NSHeight(r));// same as above
if(NSPointInRect(p,r) == NO)
return;
//if(!messageTextField) NSRunAlertPanel(@"Warning", @"messageTextField nil!", NULL, NULL, NULL);
[messageTextField setStringValue:s];
}
// awakeFromNib is called when this object is done being unpacked from the nib file;
// at this point, we can do any needed initialization before turning app control over to the user
- (void)awakeFromNib
{
// We don't actually need to do anything here, so it's empty
}
@end
マウスイベントの座標は
NSPoint p = [event locationInWindow];
であるが、イベントはウインドウのパネルのどの場所をクリックしても発生し、mouseDown に届くので、ボックス(box)以外から来るイベントを捨てる必要がある。
r = [box frame];// frame is a generic method for NSView class.
if(NSPointInRect(p,r) == NO)
return;
はそのためのコードである。
デバッグに使ったコードがコメントアウトして残されている。
ソースコードに現れる messageTextField、box の実体を Interface Builder で指定し、mouseDown をウィンドウと結びつける必要がある。
ウィンドウの属性を表示する*。
Tools → Instector を選択する>ウインドウのクラスを XMouse に変更する。すると Class Outlets に box と messageTextField が表示されるはずである。

インスペクタパネルのトップバーは Mouse Identity となっている。この Mouse はオブジェクトのクラス名 XMouse から自動的に(適当に)決定される。
このままでは、box や messageTextField の値は NULL である。これらに Interface Builder で表示されるオブジェクトの実体を結びつける必要がある。
ウインドウを controll-click すると connections panel が表示される*。この中の box をウインドウのボックスに messageTextField をウインドウのテキストフィールドに結びつける。(下図)

box をウインドウのボックスに結びつけているところ。
messageTextField は既に結びつけ終わっている。
マウスイベントで最初に戸惑うのは、イベントの発生源が Interface Builder の中で(目に見える姿で)表示されない事である。
しかし mouseDown は組み込みのメソッドなので、XMouse.m の中で上書きするだけでマウスイベントはここに来る。従って以上でプログラムは動くはずである。
ソースコードの中の mouseDown を mouseUp や mouseDragged に置き換えるだけで、これらのマウスイベントに反応するプログラムになる。
printf() を使ったデバッグに関しては XSlider に解説されている。
マウスドラッグに反応するソースコード: XMouse.zip
2009/08/04
方法 1 は無駄が含まれていたと思う。XMouse.h で定義される新しいクラスを NSBox の派生クラスとして定義し、これを Box と結びつければ幾分簡単になる。
ここではマウスドラッグに反応する Box を扱う。
XMouse.hXMouse.h を次のようにする。
#import <Cocoa/Cocoa.h>
@interface XMouse : NSBox
{
IBOutlet NSTextField *messageTextField;
}
- (void)mouseDragged:(NSEvent *)event; //Kenar
@end
XMouse.h
今度は
IBOutlet NSBox *box;
がこの中に含まれていない事に注意しよう。
XMouse.mXMouse.m は
#import "XMouse.h"
@implementation XMouse
- (void)mouseDragged:(NSEvent *)event //Kenar
{
// mouse-dragged event comes here. OK
NSString *s;
NSPoint p = [event locationInWindow];//OK
NSRect r;
s = [NSString stringWithFormat:@"(%f,%f)", p.x,p.y];
r = [self frame];// frame is a generic method for NSView class.
if(NSPointInRect(p,r) == NO)
return;
if(!messageTextField) NSRunAlertPanel(@"Warning", @"messageTextField nil!", NULL, NULL, NULL);//OK
[messageTextField setStringValue:s];//NG
}
// awakeFromNib is called when this object is done being unpacked from the nib file;
// at this point, we can do any needed initialization before turning app control over to the user
- (void)awakeFromNib
{
// We don't actually need to do anything here, so it's empty
}
@end
XMouse.m
方法 1 では
r = [box frame];// frame is a generic method for NSView class.
であったが、今度は
r = [self frame];// frame is a generic method for NSView class.
となる。また今回は余分なコメントは削除されている。
ソースコードをコンパイルし、Box のインスペクタの identity で Class を XMouse にする。

Box の identity
さらに Connections で messageTextField をウインドウの中のテキストフィールドと結びつける。

Box の Connections
コンパイルして実行する。
この第二の方法が推奨される方法であるか否かは不明である。
XMouse.m の中の
if(NSPointInRect(p,r) == NO)
return;
を削除した場合にはマウスドラッグは幾分異なった振る舞いをする。この場合にはドラッグの開始点は Box の中に制限されるが、終了点には制限が付かない。この方が使いやすい事があるかも知れない。もしも mouseDown イベントだけを扱う問題であれば、このコードは不要であろう。
マウスドラッグに反応するソースコード: XMouse1.zip
以下は参考にした URL の一覧です。