我正在尝试从 nib 加载和显示窗口,但不明白如何正确地做到这一点。 现在我使用以下代码:
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate {
var statusItem: NSStatusItem!
var statusButton: NSStatusBarButton!
var menu: NSMenu!
var menuItemTitle: NSMenuItem!
var menuItemInfo: NSMenuItem!
var menuItemQuit: NSMenuItem!
var menuImage: NSImage!
var titleView: TitleView!
func applicationDidFinishLaunching(_ aNotification: Notification) {
menuImage = NSImage(systemSymbolName: "menubar.rectangle", accessibilityDescription: "Image")
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
statusButton = statusItem.button
statusButton.image = menuImage
menuItemTitle = NSMenuItem(title: "First", action: nil, keyEquivalent: "")
menuItemInfo = NSMenuItem(title: "Info", action: #selector(actionInfo), keyEquivalent: "i")
menuItemQuit = NSMenuItem(title: "Quit", action: #selector(actionQuit), keyEquivalent: "q")
menu = NSMenu()
menu.addItem(menuItemTitle)
menu.addItem(menuItemInfo)
menu.addItem(NSMenuItem.separator())
menu.addItem(menuItemQuit)
statusItem.menu = menu
titleView = TitleView(frame: NSRect(x: 0, y: 0, width: 250, height: 70))
menuItemTitle.view = titleView
}
func applicationWillTerminate(_ aNotification: Notification) {
}
func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
@objc func actionQuit() {
NSApplication.shared.terminate(self)
}
var infoWindowController: InfoWindowController!
@objc func actionInfo() {
infoWindowController = InfoWindowController()
infoWindowController.showWindow(self)
// infoWindowController.showWin(self)
}
}
import Foundation
import Cocoa
class InfoWindowController: NSWindowController {
@IBOutlet var infoWindow: NSWindow!
@IBOutlet weak var infoIcon: NSImageView!
override var windowNibName: String! {
return "InfoWindow"
}
override func windowDidLoad() {
print("windowDidLoad")
}
func showWin(_ sender: Any) {
_ = window
showWindow(sender)
/// This does not work
// window?.center()
// window?.makeKeyAndOrderFront(self)
//This works with the first NSViewController.window access
// infoWindow?.center()
// infoWindow?.makeKeyAndOrderFront(self)
}
}
信息窗口.xib
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21701"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="InfoWindowController" customModule="GUI" customModuleProvider="target">
<connections>
<outlet property="infoWindow" destination="QvC-M9-y7g" id="jBK-DN-ufD"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2Ad-gr-Tqg">
<rect key="frame" x="185" y="166" width="56" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Hi there!" id="lZn-he-q8e">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
<point key="canvasLocation" x="105" y="144"/>
</window>
</objects>
</document>
我没有故事板,所以我使用 main.swift:
import Foundation
import Cocoa
let app = NSApplication.shared
let delegate = AppDelegate()
app.delegate = delegate
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
根据here 的文档,我需要“访问 window 属性以便调用 windowDidLoad() 和 windowWillLoad() 方法”。在执行
_ = window
行后,我观察 windowDidLoad 。但即便如此,我的控制器的 ``window` 属性仍然为零。但是 IBOutlet 开始工作了,所以我的工作代码是这样的:
func show() {
_ = window
infoWindow?.center()
infoWindow?.makeKeyAndOrderFront(self)
}
我的问题:是否可以在没有 IBOutlet 的情况下从 xib 加载和显示窗口?或者只是使用 IBOutlet,而不访问 NSWindowController 的窗口属性?如何以“正确”的方式做到这一点?而且,我怎样才能阻止用户多次激活此窗口? 谢谢!
更新:亲爱的同事们,感谢你们的帮助!我非常感激。我已经 制作了一个 github repo 以便更容易跟踪您建议我尝试的更改。
你在问多个不同的问题,这让事情变得非常混乱。从你的问题的标题来看,你似乎看到了多个信息窗口(每次你选择信息菜单项时可能会多一个)。我认为这是因为您的
actionInfo
处理程序每次调用时都会创建一个新实例。原始代码将用新实例覆盖 infoWindowController
属性。
您可以创建一次信息窗口并使用
lazy
延迟创建直到需要它:
lazy private var infoWindowController: InfoWindowController = {
InfoWindowController()
}()
@objc func actionInfo() {
infoWindowController.showWindow(self)
}
请注意,即使关闭窗口,这也会使信息窗口控制器的实例保持活动状态。
将以下代码添加到您的窗口控制器。
override init(window: NSWindow!)
{
super.init(window: window)
}
required init(coder: NSCoder)
{
super.init(coder: coder)!
}
convenience init()
{
self.init(windowNibName: "InfoWindowController", owner:(Any).self)
}
然后创建窗口;
var myWindow = InfoWindowController(windowNibName: "InfoWindowController")
myWindow.showWindow(self)
是否可以在没有 infoWindow IBOutlet 的情况下从 xib 加载和显示窗口?
是的,将xib中的File's Owner(
InfoWindowController
)的window outlet连接到window上
你不必打电话给
_ = window
。方法 windowDidLoad()
和 windowWillLoad()
将在加载窗口时自动调用,例如 showWindow
.