![4b97052b7190754f85c53dfcd99ac85d.png](https://img-blog.csdnimg.cn/img_convert/4b97052b7190754f85c53dfcd99ac85d.png)
学完本章,理论上macOS程序开发学完了。
学编程就是这么客简单,大约个把两个星期吧,就可以开始自己的项目。当然,这并不是因为我们有多厉害,而是别人早就为我们准备好了一切,我们要做的就是拿着别人做好的东西,看着说明书,东拼拼,西凑凑,糊弄出自己想要的东西。这本质上跟小朋友玩积木没任何区别。然而,如果我们真能够做出一些东西来,我们也是很厉害的,因为准备这些东西的每个家伙,他们的想法都不一样。准确地说,他们大多是各种各样的蠢。当你把这些蠢货做出的物件组装在一起,还可以用 ,且好用,那也是一种莫大的荣耀。
高尚的苹果公司也是一样的蠢。就算你一行代码都不写,他都会为你准备好Menu bar menu(菜单栏菜单)、Contextual menu(上下文菜单)、Dock menu(程序坞菜单)这三类菜单。作为一个初学者,看着那一大串的Menu bar menu(菜单栏菜单)菜单项,却没有一个能在我们的操作下有反应,真的不知道是该哭好,还是该笑好。
没错,这一章,我们要学习Menu bar menu(菜单栏菜单)、Contextual menu(上下文菜单)、Dock menu(程序坞菜单)三类菜单的设计。哦,还有Status Bar(状态栏)的菜单设计。它们的重要性我就不说了,应该是那十八般武器中的核武器。
〜〜〜〜〜 概述 〜〜〜〜〜
Xcode为macOS为你的桌面程序,提供了四类菜单以服务你的程序,它们分别是:
- Menu bar menu(菜单栏菜单):菜单栏菜单是程序所有功能的集合。这是一个约定,也就是说,我们开发的程序里所有的操作都应该可以从菜单栏的某菜单项里找到支持。
- Contextual menu(上下文菜单):也就是正文右键菜单,一般应与菜单栏的菜单项匹配。
- Dock menu(程序坞菜单):在程序坞上,右键点击程序图标显示出的菜单。
- Status Bar(状态栏)的菜单:在状态栏上,如果有,如Wifi等同。
在菜单设计中,我们需要做以下三点:
- 增删改菜单项:增删改各级菜单项,并提供支持事件;
- 增删改菜单快捷键:增删改菜单快捷键,并确认响应支持事件;
- 监听、接收并处理菜单的支持事件。
下面我们将从上述的三个方面来学习如何设计菜单。
〜〜〜〜〜 正文 〜〜〜〜〜
一、重新建立一个名为“iWriter”的macOS工程。
删除原“iWriter”工程文件,依所学再建一个macOS工程,还叫“iWriter”。同时在Storyboard上为ViewController添加一个组件“Scrollable Text View”,并约定各边离ViewController边缘为20。
- 打开Document Outline,显示出Application Scene栏的Main Menu子项。Main Menu就是Menu bar menu,所有项目如图所示:
![b751563f9c31fdb40ccf4cf8d514eec6.png](https://img-blog.csdnimg.cn/img_convert/b751563f9c31fdb40ccf4cf8d514eec6.png)
二、Menu bar menu(菜单栏菜单),菜单项的增删改与快捷键设定。
Menu bar menu(菜单栏菜单),增。
- 从Library窗口里中找到Menu Item组件。
- 拖到Storyboard的菜单条上,菜单条会位移出一段空格。注意,我这里是不能拖到Document Outline的Application Scene栏的Main Menu上,一放,Xcode就退出。
- Application Scene栏的Main Menu上显示有新添的Item。
- 再从Library窗口里找到Menu组件,将其拖到Application Scene栏中刚才新添的Item上。看到为其添加了子菜单。
- 选择刚才的Item下的Menu项,在Attributes栏的title项中输入“Modify”,确定。我们完成了为Menu bar menu(菜单栏菜单)添加了一个顶级菜单项“Modify”。
![ff7e7163a5b249df3d0025e8b3220fe4.png](https://img-blog.csdnimg.cn/img_convert/ff7e7163a5b249df3d0025e8b3220fe4.png)
![80e62711496fb690eb1c7fa1de0d51db.png](https://img-blog.csdnimg.cn/img_convert/80e62711496fb690eb1c7fa1de0d51db.png)
![3a677572ad7bb78d65ae3a08079fdd66.png](https://img-blog.csdnimg.cn/img_convert/3a677572ad7bb78d65ae3a08079fdd66.png)
![7159f765495c857f045551e49cf4edf0.png](https://img-blog.csdnimg.cn/img_convert/7159f765495c857f045551e49cf4edf0.png)
Menu bar menu(菜单栏菜单),删。
在Document Outline或Storyboard中,如菜单项未建立关联,可选中菜单项可直接Delete。
Menu bar menu(菜单栏菜单),改。
- 在Document Outline或Storyboard中,双击菜单项后进入修改状态,可直接改名。
- 在Document Outline或Storyboard中,选中单项后,可在Attributes栏的title项中改名。
Menu bar menu(菜单栏菜单),快捷键设定,快捷键设定不能重复。
- 改Modify子菜单项Item 1为“Modify Title”,选中该项。
- 选中Attributes栏Key Equivalent项,按住你想设定的键组合即可。
![2be718e94e12ddb8c0422d71466f23a8.png](https://img-blog.csdnimg.cn/img_convert/2be718e94e12ddb8c0422d71466f23a8.png)
Menu bar menu(菜单栏菜单),分割划。
菜单分割线是一个叫Separator Menu Item的组件,增删改与Meun Item一样。
三、Menu bar menu(菜单栏菜单),菜单项事件的监听、处理。
为Menu bar menu(菜单栏菜单),菜单项的监听、处理跟其它组件如Button添加Action一样。只是个人觉得,Menu bar menu(菜单栏菜单)的菜单项处理事件应放在AppDelegate.swift文件里。
- 选择Document Outline中的Modify Title菜单项,按住键盘的“control”键,拖其到AppDelegate.swift文件中。
- 建立Action关联名为:"modifyTitle"。
- 可在Connections栏中查看到,新添了一条Action的关联。
![213e304782c5d08591594392caf9c94a.png](https://img-blog.csdnimg.cn/img_convert/213e304782c5d08591594392caf9c94a.png)
在modifyTitle中添加代码,来检查action关联是否成功。
// 应用警示框
let alert = NSAlert()
alert.addButton(withTitle: "OK")
alert.messageText = "Modify Title"
alert.informativeText = "Menu item function is normal"
alert.beginSheetModal(for: NSApp.mainWindow!, completionHandler: nil)
Build and Run。点击菜单栏Modify Title项,或使用"⇧⌘T",你将看到:
![a0bd6986f6e49b423e29a6ac78806cc0.png](https://img-blog.csdnimg.cn/img_convert/a0bd6986f6e49b423e29a6ac78806cc0.png)
恭喜你,运行成功。
- 下面我们用代码来实现一次。
Menu bar menu(菜单栏菜单)是程序菜单,需要在程序启动时准备好,所以下面代码均添加在AppDelegate.swift文件里。注意事件中的#selector()和@objc,这是个新的语法糖。
- 在applicationDidFinishLaunching()方法里,添加下列代码。
// 菜单项
let otherMenu = NSMenuItem()
// 菜单
let subMenu = NSMenu(title: "Other")
subMenu.addItem(withTitle: "Outline",
action: #selector(clickOutline), keyEquivalent: "O")
// 将菜单作为菜单项的子菜单
otherMenu.submenu = subMenu
// 将菜单项添加到一级菜单
NSApp.mainMenu?.addItem(otherMenu)
NSApp.mainMenu?.update()
2. 为新添的菜单子项添加事件方法。
@objc func clickOutline(_ sender:Any){
let alert = NSAlert()
alert.addButton(withTitle: "OK")
alert.messageText = "Show Outline"
alert.informativeText = "Menu item function is normal"
alert.beginSheetModal(for: NSApp.mainWindow!, completionHandler: nil)
}
显示的效果如下:
![48dbc6c5ed95de3c3f7edb76ff1d936a.png](https://img-blog.csdnimg.cn/img_convert/48dbc6c5ed95de3c3f7edb76ff1d936a.png)
四、Contextual menu(上下文菜单)菜单项的增删改与快捷键设定。
Contextual menu(上下文菜单),新增菜单项
将Text View以Outlet属性关联到ViewController.swift中。你需要留意,建立Outlet属性时需要从Document Outline选择Text View项拖放。如果不会的话,请面壁思过10分种后回到前一章。
- 在ViewController.swift中的viewDidLoad()里给textView视图添加Contextual menu(上下文菜单)菜单项,代码如下:
//
// ViewController.swift
// iWriter
//
// Created by Jiangyouhua on 2019/6/28.
// Copyright © 2019 Jiangyouhua. All rights reserved.
//
import Cocoa
class ViewController: NSViewController {
@IBOutlet var textView: NSTextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// 为TextView添加菜单项,注意用的是插入。
let menu = NSMenuItem(title: "Right",
action: #selector(clickRight(_:)), keyEquivalent: "R")
textView.menu?.insertItem(menu, at: 0)
textView.menu?.update()
}
@objc func clickRight(_ sender:Any){
let alert = NSAlert()
alert.addButton(withTitle: "OK")
alert.messageText = "Right"
alert.informativeText = "Right click menu item added successfully"
alert.beginSheetModal(for: NSApp.mainWindow!, completionHandler: nil)
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
显示效果如下:
![7991c1767a1d0a09f05a4a548b7f90db.png](https://img-blog.csdnimg.cn/img_convert/7991c1767a1d0a09f05a4a548b7f90db.png)
Contextual menu(上下文菜单),删除与修改菜单项。注意以下代码需要上述情境。
// 删除菜单项
textView.menu?.item(at: 1)
// 修改菜单项
let item = textView.menu?.item(at: 2)
item?.title = "Other"
五、Dock menu(程序坞菜单),Status Bar(状态栏)新增菜单。
Dock menu(程序坞菜单),新增菜单。
- 从Library窗口里拖出一个Menu组件到Storyboard的Application栏上。
- 选择Document Outline的Application项。
- 在Connections栏,选择dockMenu项右则的“+”符号,拖到Storyboard的Application栏的新添的Menu组件上,建议关联。
- 建立好关联后,表明Dock menu(程序坞菜单)添加菜单成功。
![f127f08bf8b683a69608564e46d4acd0.png](https://img-blog.csdnimg.cn/img_convert/f127f08bf8b683a69608564e46d4acd0.png)
![3fc8627bc4d26d0076cbe889b9a6a93f.png](https://img-blog.csdnimg.cn/img_convert/3fc8627bc4d26d0076cbe889b9a6a93f.png)
现在你可为菜单添加菜单项并设置监听事件,显示效果如下:
![c4a66839c51d4aa290cef25fda49556f.png](https://img-blog.csdnimg.cn/img_convert/c4a66839c51d4aa290cef25fda49556f.png)
Status Bar(状态栏),新增菜单
- 需要在AppDelegate.swift设置StatusItem项,然后设置菜单与菜单项。
//
// AppDelegate.swift
// iWriter
//
// Created by Jiangyouhua on 2019/6/29.
// Copyright © 2019 Jiangyouhua. All rights reserved.
//
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
// 设置Status bar
let statusItem = NSStatusBar.system.statusItem(
withLength: CGFloat(NSStatusItem.variableLength))
statusItem.button?.title = "Menu"
statusItem.button?.cell?.isHighlighted = true
// 添加菜单项
statusItem.menu = NSMenu()
let newItem : NSMenuItem = NSMenuItem(title: "Quit",
action: #selector(quit(_:)), keyEquivalent: "")
statusItem.menu?.addItem(newItem)
statusItem.menu?.addItem(NSMenuItem.separator())
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
@objc func quit(_ send: Any) {
NSLog("Exit")
NSApplication.shared.terminate(nil)
}
}
显示效果如下:
![9f46346fba0071bce7eb61c9d796d5e4.png](https://img-blog.csdnimg.cn/img_convert/9f46346fba0071bce7eb61c9d796d5e4.png)
macOS菜单学习只有这么多,工具栏不属于菜单领域。后面将正式开始“iWriter”工程,且这个工程将会延续到最后。
下一篇,程序原形、格式与开发说明。
让我们在这里,遇见明天的自己!姜友华