真正的問題
您如何更新
mainMenuSwiftUI 中的 以使其真正起作用?
我在 SwiftUI 中構建了一個基于 MacOS 檔案的應用程式,其中包括所有內置的檔案選單命令(即關閉、保存、復制、重命名...等)
在保存檔案之前,我驗證了結構,如果有任何驗證錯誤,我想向用戶顯示一個模式對話框。
模態對話框只是一個簡單的 OK/Cancel 對話框——“OK”意味著用戶樂于保存驗證錯誤的檔案,“Cancel”則需要停止保存操作。
所以問題是:“如何攔截內置的‘保存’選單命令來顯示此對話框?
我試圖覆寫.saveItemCommandGroup - 但這會替換所有選單項,我只想覆寫幾個命令(“保存”和“另存為”)并且不想重新實作它們(并且我不確定我是否具備這樣做的技能)
.commands {
CommandGroup(replacing: .saveItem) {
// code goes here - but removes all of the in-built menus
}
}
我試過這個解決方案(在 SwiftUI 檔案應用程式中,如何從函式中保存檔案)
并將其放入我的 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 之前設定選單。
另一個編輯
請參閱這篇文章隱藏 SwiftUI / MacOS 應用程式的編輯選單
和這個評論
想法:SwiftUI 要么有錯誤,要么他們真的不希望您洗掉 NSApp.mainMenu 中的頂級選單。SwiftUI 似乎重置了整個選單,目前無法覆寫或自定義大多數細節(Xcode 13.4.1)。CommandGroup(replacing: .textEditing) { }-esque 命令不允許您洗掉或清除整個選單。分配一個新的 NSApp.mainMenu 只會在 SwiftUI 需要時被破壞,即使你沒有指定任何命令。
uj5u.com熱心網友回復:
XCode 14.1
Swift 5
經過大量非常令人沮喪的搜索嘗試和大量代碼之后 - 我將問題簡化為只是嘗試更改save選單項的名稱 - 如果我可以這樣做 - 那么我也可以更改它的操作。
這是我是怎么做到的
我的 Tetsing 應用被稱為YikesRedux
腳步:
- 注冊
AppDelegate - 覆寫
applicationWillUpdate方法 - 將選單更新放在
DispatchQueue.main.async閉包中 - 經過幾天的搜索,你已經解決了這個問題,喜極而泣
YikesAppRedux.swift
import SwiftUI
@main
struct YikesReduxApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate // <- Don't forget the AppDelegate
var body: some Scene {
DocumentGroup(newDocument: YikesReduxDocument()) { file in
ContentView(document: file.$document)
}
}
}
AppDelegate.swift
import Foundation
import AppKit
public class AppDelegate: NSObject, NSApplicationDelegate {
public func applicationWillUpdate(_ notification: Notification) {
DispatchQueue.main.async {
let currentMainMenu = NSApplication.shared.mainMenu
let fileMenu: NSMenuItem? = currentMainMenu?.item(withTitle: "File")
if nil != fileMenu {
let saveMenu = fileMenu?.submenu!.item(withTitle: "Save")
if nil != saveMenu {
print("updated menu")
saveMenu?.title = "Save Updated"
}
}
}
}
}
我把它記下來有點笨拙 - 因為它在每次應用程式更新時運行(不是很多,但你可以在控制臺“更新選單”中看到它確實發生時列印出來)
我確實嘗試保留一個關于選單是否更新的狀態變數,嘗試不再這樣做 - 但在多檔案視窗環境中你需要跟蹤每個視窗...... (也很快就會破壞選單每當它想要的時候——所以它沒有像預期的那樣作業。)
我把選單更新代碼放在幾乎所有我能想到的地方
- 每個
AppDelegate函式覆寫 - 的初始化方法
App,ContentView - 在檔案上讀取功能/寫入功能
- 你說出來 - 我把它放在那里(我什至有一個托管控制器,一個 NSViewRepresentable)
然后我將它們一一洗掉,直到找到解決方案。
如果有一種不那么笨拙的方法來做到這一點,我會很高興。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/533647.html
標籤:代码苹果系统迅捷
上一篇:Firebase不支持macos
