真实的的问题
如何更新SwiftUI中的mainMenu
,使其真正工作?
我已经在SwiftUI中构建了一个基于MacOS文档的应用程序,其中包括所有内置的文件菜单命令(即关闭、保存、复制、重命名等)
在保存文档之前,我验证了结构,如果有任何验证错误,我希望向用户显示一个模式对话框。
模态对话框只是一个简单的确定/取消对话框-“确定”表示用户愿意保存有验证错误的文件,“取消”则需要停止保存操作。
所以问题是:“如何截取内置的”保存“菜单命令以显示此对话框?
我尝试过覆盖.saveItem
CommandGroup -但这会替换所有菜单项,我只想覆盖几个命令(“保存”和“另存为”),而不想重新实现所有命令(我不确定我是否有这样做的技能)
.commands {
CommandGroup(replacing: .saveItem) {
// code goes here - but removes all of the in-built menus
}
}
我已尝试过此解决方案(In a SwiftUI Document App, how to save a document from within a function)
并将其放入我的AppDelegate中
public func applicationDidBecomeActive(_ notification: Notification) {
let menu = NSApplication.shared.mainMenu!.items.first(where: { $0.title == "File" })!
let submenu = menu.submenu!.items.first(where: { $0.title == "Save" })!
submenu.action = #selector(showDialog)
}
@objc func showDialog() {
var retVal: Int = 0
let thisWindow: NSWindow? = NSApplication.shared.mainWindow
let nsAlert: NSAlert = NSAlert()
let cancelButton: NSButton = nsAlert.addButton(withTitle: "Cancel")
cancelButton.tag = 1
let okButton: NSButton = nsAlert.addButton(withTitle: "OK")
okButton.tag = 0
// The below code is replaced
nsAlert.beginSheetModal(for: thisWindow!) { modalResponse in
print(modalResponse)
retVal = modalResponse.rawValue
if retVal == 0 {
print("save")
} else {
print("cancel")
}
}
}
然而,它实际上并不调用showDialog
函数。
编辑/更新
更新菜单仍然有困难,但在上面的例子中,调用beginModalSheet
是不正确的,因为进程将在后台运行。更新了对runModal()
的调用,这将停止任何后台进程写入文件。
@objc func showDialog() {
let nsAlert: NSAlert = NSAlert()
let cancelButton: NSButton = nsAlert.addButton(withTitle: "Cancel")
cancelButton.tag = 1
let okButton: NSButton = nsAlert.addButton(withTitle: "OK")
okButton.tag = 0
let response: Int = nsAlert.runModal().rawValue
if response == 0 {
print("save")
NSApp.sendAction(#selector(NSDocument.save(_:)), to: nil, from: nil)
} else {
print("cancel")
}
}
我在某个地方读到过,您需要在窗口出现之前设置菜单,我还读到过,您需要在设置AppDelegate之前设置菜单。
又一次编辑
查看此帖子Hiding Edit Menu of a SwiftUI / MacOS app
和此注解
想法:SwiftUI可能有一个bug,或者他们真的不想让你删除NSApp. mainMenu中的顶级菜单。SwiftUI似乎重置了整个菜单,目前没有办法覆盖或自定义大多数细节(Xcode 13.4.1)。CommandGroup(替换:.textEditing){ }-esque命令不允许您删除或清除整个菜单。分配一个新的NSApp.mainMenu只会在SwiftUI需要时被破坏,即使您没有指定任何命令。
1条答案
按热度按时间abithluo1#
一月一日****一月一日
经过大量的超级令人沮丧的搜索尝试和大量的代码-我减少了问题,只是试图改变名称的
save
菜单项-如果我可以做到这一点-那么我可以改变它的行动以及。我是这样做的
YikesRedux
*操作步骤:
1.注册
AppDelegate
1.覆写
applicationWillUpdate
方法1.将菜单更新放在
DispatchQueue.main.async
闭包中1.经过几天的搜索,你终于解决了这个问题,喜极而泣吧
YikesAppRedux.swift
AppDelegate.swift
我把这个记下来作为一个有点kludgey -因为它运行在每个应用程序更新(这不是很多,但你可以看到打印出来的控制台“更新菜单”时,它确实发生)
我确实尝试过保留一个状态变量来指示菜单是否更新,尝试不再这样做--但在多文档窗口环境中,您需要跟踪每个窗口... (此外,swift只会在需要的时候对菜单进行重命名--因此它没有像预期的那样工作。)
我把菜单更新代码放在我能想到的几乎所有地方
AppDelegate
函数覆盖App
、ContentView
的初始化方法然后我把它们一个一个地移走,直到我找到了解决办法。
如果有一种不那么笨拙的方法来做这件事,我会很高兴的。