タイトル鶴薗賢吾のCocoaはやっぱり!出張版》#3-ウィンドウの形状変更と透明化(4)カテゴリーCocoa, 鶴薗賢吾のCocoaはやっぱり!出張版
作成日2001/9/12 14:27:55作成者新居雅行
■ ウィンドウの自前ドラッグ処理
ウィンドウのスタイルマスクでタイトルバーを無くしてしまったので、ウィンドウを移動させる手段がありません。そのため、ウィンドウ ( CustomWindow ) にマウスダウンイベントとマウスドラッグイベントに対して、ウィンドウを移動する処理を書いておく必要があります。そのためには、NSWindowのmouseDown : メソッドとmouseDragged : メソッドをオーバーライドします。ウィンドウやビューは、マウスボタンが自分自身の上で押されると、 mouseDown : メソッドが、そのままドラッグされるとmouseDragged : メソッドが呼ばれます。

■ マウスダウン処理
サンプルのmouseDown : メソッドでは、CustomWindowのinitialLocationというNSPoint型のインスタンスに、ウィンドウのどこでマウスボタンが押されたかの座標を、ウィンドウの座標系で覚えています。

// ソースファイル:CustomWindow.m
// メソッド:mouseDown :

- (void) mouseDown : (NSEvent *) theEvent
{
   : 省略
initialLocation = [ self convertBaseToScreen :
[ theEvent locationInWindow ] ]; // クリック座標を取得
   : 省略
}

mouseDown : のメソッドにはNSEventクラスのパラメータが1つ渡ってきますが、ここにイベントに関する情報が入っています。マウスボタンが押された座標はNSEventのlocationInWindowメソッドで得ることが出来ます。これは、ウィンドウの左下を原点とする座標系の値になっています。ConvertBaseToScreen : メソッドで画面の左下を原点とする座標系に変換しています。左下というのを不思議に思うかもしれませんが、Cocoaでは、左上ではなく、左下が座標原点になっています。数学で使っていた上に向かってY座標の値が増える座標系を使っています。

 ★ NSEvent : イベント発生時のマウスの位置を取得
  [書式] - (NSPoint) locationInWindow
  [出力] 返り値 : マウスの位置

 ★ NSWindow : ウィンドウ内の座標からスクリーンの座標に変換
  [書式] - (NSPoint) convertBaseToScreen : (NSPoint) aPoint
  [入力] aPoint : ウィンドウ座標での位置
  [出力] 返り値 : スクリーン座標での位置

■ マウスドラッグ処理

// ソースファイル:CustomWindow.m
// メソッド:mouseDragged :

- (void) mouseDragged : (NSEvent *) theEvent
{
   : 省略
NSPoint newOrigin; // 新しいウィンドウの位置
NSRect screenFrame = [ [ NSScreen mainScreen ] frame ]; // 画面の大きさ
NSRect windowFrame = [ self frame ]; // ウィンドウの画面での位置
   : 省略
// クリック座標を取得
currentLocation = [ self convertBaseToScreen :
[ self mouseLocationOutsideOfEventStream ] ];
   : 省略
[ self setFrameOrigin : newOrigin ]; // ウィンドウを移動
}

mouseDragged : メソッドでは、mouseDown : メソッドで記憶したマウスが最初に押された時の座標からのずれを計算して、新しいウィンドウの場所 ( 左下隅の座標 ) を計算しています。ここでのマウスの座標の取得方法は、NSWindowのmouseLocationOutsideOfEventStream を使っています。先程使った、NSEventのlocationInWindowを使っても同じ値になります。イベント ( NSEvent ) から座標を得る方法と、ウィンドウ ( NSWindow ) から座標を得る方法があるということを示したかったのでしょうか、あえて、別の方法で実装しています。

 ★ NSWindow : マウスの座標を取得
  [書式] - (NSPoint) mouseLocationOutsideOfEventStream
  [出力] 返り値 : ウィンドウ座標でのマウスの位置

計算の中で、ウィンドウの上端が、画面の上端からはみださないような処理もしています。このときのために、画面の大きさを得ていますが、これには、NSScreenクラスを使います。mainScreenメソッドで、メインスクリーンのインスタンスが得られますので、これのframeメソッドで座標を得ることが出来ます。

 ★ NSScreen : メインスクリーンを取得
  [書式] + (NSScreen *) mainScreen
  [出力] 返り値 : メインスクリーンのインスタンス

 ★ NSScreen : スクリーンの位置情報を取得
  [書式] - (NSRect) frame
  [出力] 返り値 : スクリーンの位置情報

■ メニューバーより手前に表示する
CustomWindow.mのソースの初期化メソッドの中に以下の行があります。

[ result setLevel : NSStatusWindowLevel ];

ウィンドウのレベルをセットしているメソッドですが、これは、画面の中でウィンドウが表示される高さを決めるものです。高いというのは、より手前に表示されるという意味です。NSStatusWindowLevelというのはドキュメントがまだ整備されていませんので厳密なところは分かりませんが、メニューよりもDockよりも手前で、他のアプリケーションをアクティブにしても手前に表示されますので、最も手前の部類に属するレベルであることは間違いないと思われます。ただし、ここまで手前に表示するのは、例えば、画像ビューワーのスライドショーや動画の全画面再生のような用途に限られると思います。

 ★ NSWindow : ウィンドウのレベルを変更
  [書式] - (void) setLevel : (int) newLevel
  [入力] newLevel : ウィンドウのレベル

ヘッダーを見ると、ウィンドウのレベルには以下のようなものがあります。

// ソースファイル:NSWindow.h

NSNormalWindowLevel
NSFloatingWindowLevel
NSSubmenuWindowLevel
NSTornOffMenuWindowLevel
NSMainMenuWindowLevel
NSStatusWindowLevel
NSDockWindowLevel
NSModalPanelWindowLevel
NSPopUpMenuWindowLevel
NSScreenSaverWindowLeve

■ 終わりに
前回のムービー再生で動画やMP3も再生出来るようになりましたし、今回のウィンドウの変形でスキンの機能も実現出来るようになりました。これで、面白いプレーヤーソフトが作れるための材料が揃ってきました。その他、時計やカレンダー、デスクトップマスコットなど応用範囲の広いものですので、是非いろいろと試してみてください。

最後に、1つ手抜きのためのテクニックを紹介します。今回のサンプルでは、CustomViewでウィンドウの中を描画していましたが、NSImageViewを使う手もあります。NSImageViewのBorderを枠なしにすると、NSImageView自身が透明になるため、透明色を含む画像を表示すると、そのままウィンドウも透けるのです。ただし、NSImageViewがイベントを処理してしまってウィンドウがドラッグできなくなるので、その上に、CustomViewを被せておきます。このCustomViewには何もコードは書かなくて構いません。

 

これを実行すると、以下のようになります。自分で描画をしないのならば、こちらの方が手軽かもしれませんね。

 

[鶴薗賢吾]
関連リンクCocoaはやっぱり!