不移动鼠标后将其隐藏在 Mac 应用程序中
Hide the mouse in a Mac application after not moving it
我目前正在使用 Swift 为 Mac 制作幻灯片应用程序。在这个应用程序中,我想在幻灯片放映 运行 并且鼠标有一段时间没有移动时隐藏鼠标,就像在 Quick Time Player 中所做的那样。
现在我已经尝试了很多使用 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")
}
}
}
提前致谢!
要接收 mouseMoved
事件,您需要将 NSTrackingArea
添加到视图中,您可能已经发现 setHiddenUntilMouseMoves
设置是单次设置,需要在鼠标后重新设置移动到那个状态。
我没有尝试解开您的代码,而是制作了一个演示项目,我在其中设置了一个带有视图和按钮的 window。视图颜色从红色变为绿色以显示状态。
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
}
}
}
}
}
这是怎么回事。
- 在 playing/not-playing 状态之间切换并反映在颜色状态中的简单切换动作。
- 向视图添加
NSTrackingArea
。所有者是此视图控制器,因此它将接收 mouseMoved:
事件。需要选项 .mouseMoved
来设置它。
- 不播放幻灯片时从视图中删除跟踪区域并将
setHiddenUntilMouseMoves
设置为 false。
mouseMoved:
处理程序
- 只要跟踪区域存在且尚未等待,
setHiddenUntilMouseMoves
就会在两秒后设置为真。请注意,对 self
的弱引用阻止了此处可能的保留循环。
这并不完美,因为您可能会发现光标在离开 window 后会隐藏一次,但应该会让您朝着正确的方向前进。
我目前正在使用 Swift 为 Mac 制作幻灯片应用程序。在这个应用程序中,我想在幻灯片放映 运行 并且鼠标有一段时间没有移动时隐藏鼠标,就像在 Quick Time Player 中所做的那样。
现在我已经尝试了很多使用 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")
}
}
}
提前致谢!
要接收 mouseMoved
事件,您需要将 NSTrackingArea
添加到视图中,您可能已经发现 setHiddenUntilMouseMoves
设置是单次设置,需要在鼠标后重新设置移动到那个状态。
我没有尝试解开您的代码,而是制作了一个演示项目,我在其中设置了一个带有视图和按钮的 window。视图颜色从红色变为绿色以显示状态。
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
}
}
}
}
}
这是怎么回事。
- 在 playing/not-playing 状态之间切换并反映在颜色状态中的简单切换动作。
- 向视图添加
NSTrackingArea
。所有者是此视图控制器,因此它将接收mouseMoved:
事件。需要选项.mouseMoved
来设置它。 - 不播放幻灯片时从视图中删除跟踪区域并将
setHiddenUntilMouseMoves
设置为 false。 mouseMoved:
处理程序- 只要跟踪区域存在且尚未等待,
setHiddenUntilMouseMoves
就会在两秒后设置为真。请注意,对self
的弱引用阻止了此处可能的保留循环。
这并不完美,因为您可能会发现光标在离开 window 后会隐藏一次,但应该会让您朝着正确的方向前进。