2017-01-01 113 views
3

我目前正在使用Swift为Mac制作幻灯片应用程序。在这个应用程序中,我想隐藏鼠标,而幻灯片正在运行,并且鼠标还没有移动一段时间,就像在Quick Time Player中完成的一样。将鼠标移动到Mac应用程序后不移动它

现在我已经尝试了一系列使用NSCursor.hide()NSCursor.unhide()以及NSCursor.setHiddenUntilMouseMoves()的方法,但没有很好用。

首先,我没有让它在我的主ViewController中调用mouseMoved函数,其次NSCursor.setHiddenUntilMouseMoves()似乎并不总是工作,即使我没有触及我的触控板。在代码更改幻灯片中的图像后,我发现图像被更改,但使用调试器时,它并不会停留在该行代码上,而不会隐藏光标。

有人能告诉我一个如何使这个工作的一般方法吗?我很确定这不是一件奇特的事情,有很多简单的方法可以做到这一点。

以下是我已经试过:

import Cocoa 

class DiashowViewController: NSViewController { 

    enum DiashowState { 
     case playing 
     case paused 
     case stopped 
    } 

    var files: [URL]? 
    var diaTimer = Timer() 
    var diashowState: DiashowState = .stopped 

    var mouseTimer = Timer() 

    @IBOutlet weak var diaView: NSImageView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

    } 

    override var representedObject: Any? { 
     didSet { 
     // Update the view, if already loaded. 

     } 
    } 

    func playDiashow() { 
     if diashowState == .paused { 
      diaTimer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.changeDia), userInfo: nil, repeats: true) 
      diashowState = .playing 
      NSCursor.setHiddenUntilMouseMoves(true) 
     } 
    } 

    func playDiashow(withFiles files: [URL]) { 
     stopDiashow() 

     self.files = files 
     diashowState = .paused 

     playDiashow() 
     changeDia() 
    } 

    func pauseDiashow() { 
     if diashowState == .playing { 
      diaTimer.invalidate() 
      diashowState = .paused 
     } 
    } 

    override func mouseMoved(with event: NSEvent) { 
     print("MOUSE MOVED") 
    } 

    func stopDiashow() { 
     pauseDiashow() 
     diaView.image = nil 
     files = nil 
     diashowState = .stopped 
    } 

    func changeDia() { 
     if diashowState == .playing { 
      let i = Int(arc4random_uniform(UInt32(files!.count))) 
      let thisDiaURL = files![i] 
      let thisDia = NSImage(contentsOf: thisDiaURL) 
      thisDia?.size = NSSize(width: (thisDia?.representations.first?.pixelsWide)!, height: (thisDia?.representations.first?.pixelsHigh)!) 
      diaView.image = thisDia 
      NSCursor.setHiddenUntilMouseMoves(true) 
      print("HIDE MOUSE") 
     } 
    } 

} 

非常感谢提前!

+1

请粘贴你试过的代码 – Alistra

+0

对不起,你去了! –

回答

2

要接收mouseMoved事件,你需要一个NSTrackingArea添加到视图,你可能已经发现了setHiddenUntilMouseMoves设置为单发,需要之后,这些状态的鼠标移动到被重申。

而不是试图解开你的代码我做了一个演示项目,我设置了一个视图和一个按钮的窗口。视图将颜色从红色变为绿色以显示状态。

enter image description here

class ViewController: NSViewController { 

    @IBOutlet weak var xview: NSView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     xview.wantsLayer = true 
    } 

    //1. 
    var isPresentingSlideshow = false 
    @IBAction func toggle(_ sender: Any) { 

     if(isPresentingSlideshow) { 
      isPresentingSlideshow = false 
      xview.layer?.backgroundColor = NSColor.green.cgColor 
      teardownTracking() 
     } 
     else { 
      isPresentingSlideshow = true 
      xview.layer?.backgroundColor = NSColor.red.cgColor 
      setupTracking() 
     } 
    } 

    //2. 
    var trackingArea:NSTrackingArea? 
    func setupTracking() { 
     let area = NSTrackingArea(rect: xview.bounds, options: [.activeAlways,.mouseEnteredAndExited,.mouseMoved,.inVisibleRect] , owner: self, userInfo: nil) 
     xview.addTrackingArea(area) 
     trackingArea = area 
    } 

    //3. 
    func teardownTracking() { 
     if let trackingArea = trackingArea { 
      xview.removeTrackingArea(trackingArea) 
      self.trackingArea = nil 
      NSCursor.setHiddenUntilMouseMoves(false) 
     } 
    } 

    //4. 
    var cursorHideState = false 
    override func mouseMoved(with event: NSEvent) { 
     super.mouseMoved(with: event) 

     if !cursorHideState { 
      cursorHideState = true 
      //5. 
      DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { 
       [weak self] in 
       if let _ = self?.trackingArea { 
        NSCursor.setHiddenUntilMouseMoves(true) 
        self?.cursorHideState = false 
       } 
      } 
     } 
    } 

} 

什么这里发生的。

  1. 简单的切换动作可以在播放/不播放状态之间进行切换,并可以在色彩状态下进行反映。
  2. 在视图中添加NSTrackingArea。所有者是该视图控制器,因此它将收到mouseMoved:事件。需要选项.mouseMoved来设置。
  3. 当幻灯播放未播放时,从视图中删除跟踪区域,并将setHiddenUntilMouseMoves设置为false。
  4. mouseMoved:处理程序
  5. 只要跟踪区域存在且尚未等待,setHiddenUntilMouseMoves在两秒后设置为真。请注意,对self的弱引用可防止可能的保留周期。

这并不完美,因为您可能会发现光标在离开窗口后隐藏了一次,但应该让您朝着正确的方向前进。

+0

非常感谢,这正是我一直在寻找的! 可以使用Timer而不是DispatchQueue吗?还是有很好的理由在Timer上使用它? –

+0

你也可以在这里使用计时器。我的偏好是DispatchQueue作为保留语义是一个更清晰的国际海事组织。但对于他们自己:-) –

+0

我试过你的解决方案,它似乎工作奇妙,除了'setHiddenUntilMouseMoves'调用似乎不隐藏光标。我只偶尔看到光标被隐藏。我知道这个函数被调用,因为程序在正确的时刻停下来放置一个断点,而在它下面调用'print'right也会在正确的时间被调用。 有什么想法? –