2017-01-01 5 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은 추적 영역이 존재하며 대기하지 않는 한 2 초 후에 true로 설정됩니다. self에 대한 약한 참조는 여기에서 가능한 유지주기를 방지합니다.

커서가 창을 벗어난 후 한 번 숨겨 지지만 올바른 방향으로 가야한다는 것을 알기에 이것은 완벽하지 않습니다.

+0

고마워, 그게 내가 찾고 있던거야! DispatchQueue 대신 Timer를 사용할 수 있습니까? 아니면 Timer를 통해 사용해야할까요? –

+0

여기에도 타이머를 사용할 수 있습니다.retain semantics가 조금 더 명확한 IMO이기 때문에 나의 선호는 DispatchQueue를위한 것이다. 하지만 각자 자신의 :-) –

+0

나는 당신의 솔루션을 시도하고 그것을 제외하고 멋지게 작동하지 않는 것'setHiddenUntilMouseMoves'의 호출은 커서를 숨기지 않는 것 같습니다. 가끔 커서가 숨겨져있는 경우가 있습니다. 나는 함수가 호출되었음을 알고있다. 왜냐하면 프로그램이 중단 점에 대한 적절한 순간에 멈추고 그 아래에있는'print'right 호출이 적절한 때에 호출되기 때문이다. 아이디어가 있으십니까? –