Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Dezy

macrumors newbie
Original poster
Jul 13, 2021
22
0
I don't understand how programmers identify if a user has clicked on a macos menu item. The examples I've seen put the CommandMenu code and the action in the "main" swift file. But I don't get it, how can this work? Don't I have to write some code in the ContentView file to see if the user has clicked on a particular menu item?

I want to do something like this....

01: menuitem text = "Change Font"
02: Add the menu item.
03: If the user clicks on "Change Font" show an alert.

I just don't get it, so if anyone can help that would be great.
 
Hi there, Dezy :)

Let's take this in smaller chunks

1)
Just a clarification here. - I know you're using SwiftUI based on the context of what you're saying and your last post. But for questions like this that's important context, since how you might do things varies a lot depending on the framework you use.

2)
Another little clarification, "ContentView" isn't strictly speaking a thing. It's just a default name. You can call it anything you want. It's just the default template name for the main View in Apple's template.

3)
Which leads us to: Why do you feel like you need code inside the ContentView struct as well? The menu items can be pretty independent from your main view. If you want you can set up state in the view that gets changed when the menu item is pressed to then update the view, but if you want to show an alert or dialogue box it can be entirely separate from that view so you won't need that.
Really, for the most part you can place code wherever you want as long as you tie things together. That's where the practice of architecture comes into play. Arguably one of the most important aspects of programming; Being able to architect the structure of your code in a manageable way. Nothing is prescribed in advance, the structure is yours to define to a great extend.

4)
More general and abstract response here. Do not think about your code here this is all general and abstract in regards to your broader question; How we can know when something has been clicked.
There are essentially two ways of detecting button presses. Polling and event-driven handling. What you want is almost always event driven, but I'll go through both.
In polling, every CPU timeslice your program gets, it checks to see if the button is being clicked. It's essentially
Code:
while(true) {
    if(button.isClicked) { 
         reactToButtonClick()
    }
}
(That was pseudo code)

In event-driven code what you instead do is you set up an event listener or "observer". so that the system lets you know when events happen. It's a pretty clever and powerful trick, where instead of every program checking their own state, the system just checks for button pushes and sends messages to all listeners when events happen.
To bring it a little back to your code, this is already the behaviour you see if you have buttons in your ContentView struct with attached behaviour. They are using an observer pattern behind the scenes. The button object has a list of listeners, and whenever it's clicked, it calls an action method on all its listeners which you can then define for the button.

5)
The concrete:

If you want to add a menu bar item that shows an alert to your app, here's one approach

Swift:
//


//  SwiftUITest2App.swift


//  SwiftUITest2


//


//  Created by Casper Sørensen on 22/07/2021.


//





[B]import[/B] SwiftUI





[B]@main


struct[/B] SwiftUITest2App: App {


    @State [B]private[/B] [B]var[/B] isShowingAlert = [B]false[/B]


    [B]var[/B] body: [B]some[/B] Scene {


        WindowGroup {


            ContentView().alert(isPresented: $isShowingAlert, content: {


                Alert(title: Text("UhOh! You clicked the button!"), message: Text("Now you'll have to click OK to get it to go away again"), dismissButton: .default(Text("OK")))


            })


            


        }


        .commands {


            CommandMenu("Click Me") {


                Button("This will trigger alert…") {


                    isShowingAlert = [B]true[/B]


                }


            }


        }


    }


}

Sorry for the annoying formatting, it happens when I spy from Xcode.

Now there's a little catch here. - This only works when the ContentView is visible. If you close the view's window, no alert will be shown when the menu bar item is clicked, because the alert is tied to the content view. Unfortunately SwiftUI cannot present stand alone alerts not tied to a view at this time. A workaround would be to, instead of using an "Alert", you can build an Alert yourself and just instantiate that view when the command button is clicked instead. That should work globally. But this will present the alert when the menu bar item is clicked and the main view is not closed.
 
Hi casperes1996 (aka: Casper) :)

Thanks for dropping by!

Okay, first things first..... Do you prefer being called casperes1996 or Casper? Casper sounds cooler if you ask me.

Secondly.....

Point 1 = Okay I got it, sort of, when you say 'SwiftUI' you mean the SwiftUI lifecycle right?

Point 2 = Got it.

Point 3 =

"Why do you feel like you need code inside the ContentView struct as well?"

Long story short, I'm kind of dumb.

But I will try to remember 'tie things together' and 'architecture'.

Point 4 = Got it.

Point 5 = Ohhhhh, so you CAN have code in the upper file (the file that's not called ContentView.swift) and that code can be triggered or activated by an event such as clicking on it. Okay.... Got it.

I'm going to play around with your code and try a few things out. So thanks for the reply casperes1996/Casper and of course the code (that's the stuff that really helps me) and if I get stuck doing menu stuff I'll post here again. Bye for now!
 
Okay, first things first..... Do you prefer being called casperes1996 or Casper? Casper sounds cooler if you ask me.
Casper's fine. It's my name and I use it a lot of places online. Casperes1996 is a common username for me, but I don't think of it as a "name", it's more just a login. It's just my name, Casper, my middle and sur name initials, E, S, and birth year :)
Point 1 = Okay I got it, sort of, when you say 'SwiftUI' you mean the SwiftUI lifecycle right?
I think both can be relevant to mention in technical questions, but mentioning the SwiftUI lifecycle is more important probably, since it can determine a lot about how the app will integrate with the system, and you can mix and match SwiftUI and AppKit code with the right wrappers. But I'd general advice saying "I'm writing SwiftUI using the SwiftUI lifecycle" in your technical questions so people have that context for answering you. Otherwise you might get answers that don't, at least on the surface, help very much.
"Why do you feel like you need code inside the ContentView struct as well?"

Long story short, I'm kind of dumb.

But I will try to remember 'tie things together' and 'architecture'.
There's nothing dumb about it. Nobody's an expert when they start. I wasn't asking to make you feel dumb, just to understand the mindset to better help explain things :)
Point 5 = Ohhhhh, so you CAN have code in the upper file (the file that's not called ContentView.swift) and that code can be triggered or activated by an event such as clicking on it. Okay.... Got it.

I'm going to play around with your code and try a few things out. So thanks for the reply casperes1996/Casper and of course the code (that's the stuff that really helps me) and if I get stuck doing menu stuff I'll post here again. Bye for now!
You can basically have code that gets triggered on events anywhere. Generally you put the event trigger code by the input in SwiftUI, like you see within the button it changes the state of the isShowingAlert boolean. But the function that it calls/the state it changes can really be anywhere.

Playing around and experimenting for yourself is always a good way of learning and seeing how things can work.
 
Uh huh, well that clears some things up.

And I should also mention that it never crossed my mind that you were asking me to make me feel dumb. I get it, a lot of the times I actually am dumb. In fact, I'm probably the dumbest guy here! And that's fine by me :)

No Casper, you've been more than helpful and I appreciate that.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.