swift 从NIB显示窗口防止多个示例

e4eetjau  于 2023-04-19  发布在  Swift
关注(0)|答案(3)|浏览(141)

我试图从笔尖加载和显示窗口,不知道如何正确地做到这一点。现在我使用以下代码:

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)
    }
}

InfoWindow.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`属性仍然为nil。但IBOutlet开始工作,所以我的工作代码如下所示:

func show() {
        _ = window
        infoWindow?.center()
        infoWindow?.makeKeyAndOrderFront(self)
    }

我的问题是:有没有可能在没有IBOutlet的情况下从xib加载并显示窗口?或者只使用IBOutlet,而不访问NSWindowController的window属性?如何以“正确”的方式进行?还有,我如何防止用户多次激活此窗口?谢谢!
更新:亲爱的同事,谢谢你的帮助!我非常感激。我已经made a github repo,使它更容易跟踪您建议我尝试的更改。

hfsqlsce

hfsqlsce1#

你问了很多问题这让事情变得非常混乱。从你的问题的标题来看,你似乎得到了多个信息窗口正在显示我认为这是因为每次调用actionInfo处理程序时都会创建一个新的示例。原始代码将使用新示例覆盖infoWindowController属性。
您可以创建一次Info窗口,然后使用lazy延迟创建,直到需要它:

lazy private var infoWindowController: InfoWindowController = {
        InfoWindowController()
}()
@objc func actionInfo() {
    infoWindowController.showWindow(self)
}

请注意,这将使信息窗口控制器的示例保持活动状态,即使您关闭窗口。

yfjy0ee7

yfjy0ee72#

将以下代码添加到窗口控制器中。

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)
yhuiod9q

yhuiod9q3#

是否可以在没有infoWindow IBOutlet的情况下从xib加载和显示窗口?
是的。InfoWindowController有一个outlet属性infoWindowInfoWindowController的超类NSWindowController有一个属性window。在xib中,infoWindow的outlet连接到窗口,但window的outlet没有。
解决方案:将xib中的window插座连接到窗口。
步骤:
1.选择InfoWindow.xib
1.选择文件的所有者
1.转到连接检查器
1.从窗口出口拖动到窗口

你不需要调用_ = window。当窗口加载时,方法windowDidLoad()windowWillLoad()会被自动调用,例如showWindow

相关问题