3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

NSViewのmouseEnteredとmouseExitedの有効化をProtocol Extensionで実装してみる

Last updated at Posted at 2017-05-10

デフォルトでは無効化されているイベント

NSViewのmouseEnteredやmouseExitedはデフォルトでは無効化されており、有効化させるには
1.NSViewのupdateTrackingAreasをoverrideし、
2.NSView自身のサイズと同じ領域でaddTrackingAreaメソッドを用いてNSTrackingAreaを指定する
という手順をふむ必要があります。

override func updateTrackingAreas() {
    
    //すでに指定済みのtrackingAreaを一旦解除しておく
    if !trackingAreas.isEmpty {
        for area in trackingAreas {
            removeTrackingArea(area)
       }
    }

    //自分のsizeが0ならば何もしない
    if bounds.size.width == 0 || bounds.size.height == 0 { return }
        
    //トラッキングオプションを指定(Enter / Exit と一緒に Moved も対象にしてます)
    let options: NSTrackingAreaOptions = [
                 .mouseEnteredAndExited,
                 .mouseMoved,
                 .activeInActiveApp,
                 .assumeInside
    ]
    //NSTrackingAreaのインスタンスを作り、addTrackingAreaで指定
    let area = NSTrackingArea(rect: bounds, options: options, owner: self, userInfo: nil)
    addTrackingArea(area)  
 }

コピペだと芸がありませんし、SuperClassに機能を持たせてもいいのですが、NSButtonなどを拡張したい場合も考えて、ここはひとつProtocol Extensionで実装をまとめてしまいましょう。

NSTrackingAreaを有効化するメソッドをプロトコルに実装するよ

//空のプロトコルを定義
protocol MouseTrackableView {}

//MouseEnter や Exit Moveのイベントを有効化させる機能を持ったプロトコル拡張でNSViewにのみ有効にする
extension MouseTrackableView where Self: NSView {
    /*
    現在のrectに合わせてTrackingAreaを更新するメソッド
    このプロトコル拡張では複数のTrackingAreaを保持することは許容しておらずに
    renewTrackAreaを呼び出したタイミングで、必ず自身のRectに合わせたTrackingAreaを
    一つだけ保持することになる
    */
    func renewTrackArea() {
        //すでに指定済みのtrackingAreaを一旦解除しておく
        if !trackingAreas.isEmpty {
            for area in trackingAreas {
                removeTrackingArea(area)
            }
        }

        //自分のsizeが0ならば何もしない
        if bounds.size.width == 0 || bounds.size.height == 0 { return }
        
        //トラッキングオプションを指定(Enter / Exit と一緒に Moved も対象にしてます)
        let options: NSTrackingAreaOptions = [
                 .mouseEnteredAndExited,
                 .mouseMoved,
                 .activeInActiveApp,
                 .assumeInside
        ]
        //NSTrackingAreaのインスタンスを作り、addTrackingAreaで指定
        let area = NSTrackingArea(rect: bounds, options: options, owner: self, userInfo: nil)
        addTrackingArea(area)  
    }
}

使い方

後は、updateTrackingAreasをoverrideします

class MouseEventView: NSView, MouseTrackableView {
    override func updateTrackingAreas() {
        renewTrackArea()
    }
    override func mouseEntered(with theEvent: NSEvent) {
        NSLog("mouseEntered")
    }
    override func mouseExited(with theEvent: NSEvent) {
        NSLog("mouseExited")
    }
}
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?