🐰

NSWindowの移動やイベント処理を制御するポイント

2024/02/24に公開

ウインドウをおおよそ中央配置する

NSWindowのメソッドcenter()を使うと、ウインドウの表示位置を所属スクリーンの中央付近に移動します。水平方向には中央配置になり、垂直方向にはやや上方向に位置するようになります。垂直方向が完全な中央ではない理由は、システムが視覚的なバランスを考慮するためだそうです。

このメソッドはまだ表示されていないウインドウを表示する機能は持たないため、あらかじめmakeKeyAndOrderFront(_:)で最前面に表示しておく必要があります。

ウインドウの移動可能性を制御する

NSWindowのプロパティisMovableを使うと、ユーザーによるウインドウの移動を制限します。プログラムでframeを変更する等の制御は引き続き有効です。

falseを設定すると次のmovableByWindowBackgroundは無効になります。

ウインドウの背景を掴んで移動する

NSWindowのプロパティisMovableByWindowBackgroundを使うと、タイトルバーだけではなくウインドウの背景をどこでも掴んで移動できるようになります。大きさが比較的小さめのユーティリティ系のウインドウで使うと良いでしょう。

ちなみに古いMac OS XではBrushed Metalスタイル(texturedスタイル、NSTexturedBackgroundWindowMask)のウインドウでmovableByWindowBackgroundが有効になっていました。

ビューへのマウスイベントをウインドウの移動処理にパスする

NSViewのgetterプロパティmouseDownCanMoveWindowを使うと、カスタムビューに対するmouseDownをウインドウを掴んで移動する処理にもパスします。カスタムビュー側のmouseDownも同時に呼ばれることに注意しましょう。

この挙動を有効にするにはサブクラスでオーバーライドしてtrueを返します。

クリックスルーによって直接マウスイベントを受け取る/受け取らない

非アクティブのウインドウ内のビュー要素をクリックした際に、そのイベントをビューに渡して処理するかどうかを制御することができます。NSButtonやNSSliderなどAppKitの一部のコントロールでは、所属するウインドウが後ろ側にあってもその上で起きたクリックを直接処理できます。これをクリックスルーと言います。

通常のビューではクリックスルーを拒否する挙動になっており、非アクティブのウインドウ内の要素をクリックしても、そのイベントはビューに到達せずにただウインドウをアクティブにして終了します。

macOSのUIシステムはクリックスルーを制御することによって、ユーザー操作のクリック暴発をうまく防いでいます。


クリックスルーの挙動を制御するには、NSViewのacceptsFirstMouse(for:)メソッドをオーバーライドします。trueを返すとクリックスルーを有効にします。すなわち、ボタン要素のように所属ウインドウが後ろ側にあってもそのビューへのクリックを直接受け取れるようになります。

関連:Handling Mouse Events - Cocoa Event Handling Guide

Discussion