0

I need to add a menu item at the place where for example XCode place's the "Window" -> "Developers Documentation" menu item is available. This Menu Item needs a short cut and a checkmark if the window is open. Also the menu Item should close the window when chosen again.

For now I use.

import SwiftUI
import Foundation
import Combine

@main
struct Navigate_DetailApp: App {

@StateObject var listItemsViewModel : ItemModelView = ItemModelView()
@StateObject var appState = AppState()
@State var isProductWindowOpen = false

let someWindow = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 380, height: 300), styleMask: [.titled, .closable],  backing: .buffered, defer: false)


var body: some Scene {

    WindowGroup ("New") {
        ContentView(appState: appState)
            .frame(minWidth: 800, maxWidth: 900, minHeight: 500, maxHeight: 600)
            .environmentObject(listItemsViewModel)
    }

   WindowGroup("Products") {
            ProductsView()
        }
        Toggle("Products-toggle", isOn: $isProductWindowOpen)
                .onChange(of: isProductWindowOpen) { ison in
                    print("isON")
                    if ison {
                        print("open")
                        someWindow.contentView = NSHostingView(rootView: ProductsView())
                        someWindow.makeKeyAndOrderFront(nil)
                    } else {
                        print("close")
                        someWindow.close()
                    }
                }                               
            .keyboardShortcut("0")
            Button("Products-but open") {
                //OpenWindows.ProductsView.open()
                print("Menu Button Open")
                someWindow.contentView = NSHostingView(rootView: ProductsView())
                someWindow.makeKeyAndOrderFront(nil)
            }
            .keyboardShortcut("1")
            Button("Products-but close") {
                print("Menu Button Close")
                someWindow.close()
            }
            .keyboardShortcut("2")

            Button("Products-but open/") {
                print("Menu Button OpenClose Toggle")
                isProductWindowOpen.toggle()
                if isProductWindowOpen == true {
                    print("open")
                    someWindow.contentView = NSHostingView(rootView: ProductsView())
                    someWindow.makeKeyAndOrderFront(nil)
                } else {
                    print("close")
                    someWindow.close()
                }
            }
            .keyboardShortcut("3")

.... OLD CODE
    func openProductsWindow() {
        someWindow.contentView = NSHostingView(rootView: ProductsView())
        self.someWindow.makeKeyAndOrderFront(nil)
    }
    func closeProductsWindow() {
        .... ?? how to close the window
    }

....

struct ProductsView: View {
    var body: some View {
        Text("Products")
            .frame(minWidth: 600, maxWidth: 600, minHeight: 400, maxHeight: 400)
    }
}

What do I need to change to accomplish the placement of the menu item and let it close the window.

EDIT =================

Again thank you, it clarifies some issue's. Unfortunate it doesn't work. Did change some code to try to get it working but same effect; nothings happens. Looking with the debugger, it never comes to the action or print statement.

With the added Buttons and their code it works, for only one time. Meaning if I use the 'button open' it opens the ProductsView, if I use 'Button Close', it closes the window, but then it doesn't open it any more, however it shows the print statement in the debugger. What can I do to get both working, the Toggle and multiply using the Buttons ( No Checkmark ) ?

With the Button and then let it toggle, it works also only one time. Open and Close, but then its over, no more open or close window. The debugger shows:

Menu Button OpenClose Toggle
open
Menu Button OpenClose Toggle
close
Menu Button OpenClose Toggle
open
Menu Button OpenClose Toggle
open
Menu Button OpenClose Toggle
close

=========

Step Forward - New Code that works, but..

I did move the State to a StateObject blah blah, and that works okay, I show the code. But why does your code works for you but not for me?

@main
struct menuItemInsertWindowApp: App {

    @StateObject var productMenuState = MenuState()

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        WindowGroup("Products") {
            ProductsView()
        }
        .commands {
            CommandGroup(replacing: .windowList) {
                ProductMenuItem(productMenuState: productMenuState)
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        Text("ContentView")
            .frame(minWidth: 600, maxWidth: 600, minHeight: 400, maxHeight: 400)
    }
}

struct ProductsView: View {
    var body: some View {
        Text("Products")
            .frame(minWidth: 500, maxWidth: 600, minHeight: 300, maxHeight: 400)
    }
}

class MenuState : ObservableObject {
    @Published var isProductWindowOpen = false
}

struct ProductMenuItem : View {
    let someWindow = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 600, height: 400), styleMask: [.titled, .closable], backing: .buffered, defer: false)

    @ObservedObject var productMenuState : MenuState

    var body: some View {
        Toggle("Products - Toggle That Works", isOn: $productMenuState.isProductWindowOpen)
            .onChange(of: productMenuState.isProductWindowOpen) { value in
                print( "change isProductWindowOpen" )
                if value {
                    print( "ProductWindow Opens" )
                    someWindow.contentView = NSHostingView(rootView: ProductsView())
                    someWindow.makeKeyAndOrderFront(nil)
                } else {
                    print( "ProductWindow Closes" )
                    someWindow.close()
                }
            }
    }
}

It Works however if you look at the XCode log it shows some strange double called line's. Is this because of a macOS bug or XCode compiling bug or.... Is this solvable?

change isProductWindowOpen
ProductWindow Opens
change isProductWindowOpen
ProductWindow Opens

change isProductWindowOpen
ProductWindow Closes
change isProductWindowOpen
ProductWindow Closes
change isProductWindowOpen
ProductWindow Closes

onChange(of: Bool) action tried to update multiple times per frame.
onChange(of: Bool) action tried to update multiple times per frame.

change isProductWindowOpen
ProductWindow Opens
change isProductWindowOpen
ProductWindow Opens

onChange(of: Bool) action tried to update multiple times per frame.
onChange(of: Bool) action tried to update multiple times per frame.
onChange(of: Bool) action tried to update multiple times per frame.

change isProductWindowOpen
ProductWindow Closes
change isProductWindowOpen
ProductWindow Closes
 

Also later, duplicate windows of the window shows up, as well when I rapidly pressing the shortkeys.

Any suggestions?

1 Answer 1

2

to "...add menu item inside window menu", you could try this approach:

        CommandGroup(replacing: .windowList) {
            Button("Products") {
                print("----> clicked Products")
            }
        }

EDIT-1: given your new code, you could also try this, or something similar (adjust according to your needs):

        CommandGroup(replacing: .windowList) {
            Toggle("Products", isOn: $isProductWindowOpen)
                .onChange(of: isProductWindowOpen) { ison in
                    if ison {
                        someWindow.contentView = NSHostingView(rootView: ProductsView())
                        someWindow.makeKeyAndOrderFront(nil)
                    } else {
                        someWindow.close()
                    }
                }
        }

EDIT-2: this is the test code that works well for me.

import SwiftUI

@main
struct TestApp: App {
    let someWindow = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 600, height: 400), styleMask: [.titled, .closable], backing: .buffered, defer: false)
    
    @State var isProductWindowOpen = false
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        WindowGroup("Products") {
            ProductsView()
        }
        .commands {
            CommandGroup(replacing: .windowList) {
                Button("Products open") {
                    print("Products Button Open")
                    someWindow.contentView = NSHostingView(rootView: ProductsView())
                    someWindow.makeKeyAndOrderFront(nil)
                } .keyboardShortcut("1")
                
                Button("Products close") {
                    print("Products Button Close")
                    someWindow.close()
                }.keyboardShortcut("2")
                
                Button("Products toggle") {
                    print("Products toggle")
                    isProductWindowOpen.toggle()
                    if isProductWindowOpen {
                        print("open")
                        someWindow.contentView = NSHostingView(rootView: ProductsView())
                        someWindow.makeKeyAndOrderFront(nil)
                    } else {
                        print("close")
                        someWindow.close()
                    }
                }.keyboardShortcut("3")
            }
        }
        
    }
}

struct ProductsView: View {
    var body: some View {
        Text("Products")
            .frame(minWidth: 600, maxWidth: 600, minHeight: 400, maxHeight: 400)
    }
}

struct ContentView: View {
    var body: some View {
        Text("ContentView")
            .frame(minWidth: 600, maxWidth: 600, minHeight: 400, maxHeight: 400)
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Hi, thank you very much. I did update the code, because I can't get it to work. Please can you give it a look what I do wrong or doesn't understand.
updated my answer with more sample code. That code works well for me, that is, it opens, closes and toggles the ProductsView window from the Window menu.
Hi, Thank you for your time. Doesn't work for me. Did create a new project; copied your code but got the same behaviour as before. Toggle doesn't work. The buttons do only one time. - I am using a MBP Retina 2015 with macOS 12.5 and XCode Version 13.4.1 (13F100) with XCode 12 compatible format.
workingdog support Ukraine : I did get it to work - See my question updated. Do you know why this happens.
Don't know why you have those warnings. Try using, @State var isProductWindowOpen like you used to, instead of the class MenuState : ObservableObject, since that works in my code. Pass it to the ProductMenuItem as a binding.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.