在单击的位置添加新标签 SWIFT

Adding a new label where clicked SWIFT

我想为 MacOS 应用程序编写一个简单的 swift 代码,它会在用户在 window.

中执行鼠标单击的任何地方添加一个新标签

此代码编译但使应用程序崩溃:

@IBOutlet var here2 = [NSTextField]()
var count: Int = 0
func getCoordinates(){
        NSEvent.addLocalMonitorForEvents(matching: [.leftMouseDown]) {
        if self.location.x < 700 && self.location.y<750 {
            self.here2.append(NSTextField.init())
            self.here2[self.count].frame.origin = CGPoint(x: self.location.x, y: self.location.y)
            self.here2[self.count].stringValue = String(self.count)
            print("count is: " + String(self.here2.count))
            self.count+=1
        }
        return [=11=]
    }

您不能在 NSTextView 上调用 copy,这会导致错误消息。

您可以通过对视图进行子类化来实现所有必需的方法,但我建议您以编程方式分配新的文本视图,并在代码中而不是在界面生成器中设置它们的样式。

这是另一个处理复制对象的线程:"[something copyWithZone:]: unrecognized selector sent to instance" when using Bindings / Core Data

这是一种编程方法,可能在终端中 运行。请注意,window.acceptsMouseMovedEvents 设置为 true。

//May be run in Terminal with:
//swiftc label.swift -framework Cocoa -o label && ./label

import Cocoa

class AppDelegate: NSObject, NSApplicationDelegate {
var window : NSWindow!
var here2 = [NSTextField]()
var count: Int = 0
let _wndW : CGFloat = 700
let _wndH : CGFloat = 750
let _labelW : CGFloat = 24
let _labelH : CGFloat = 24

@objc func getCoordinates(_ sender:AnyObject ) {
 NSEvent.addLocalMonitorForEvents(matching: [.leftMouseDown]) {
var pt: NSPoint? { self.window.mouseLocationOutsideOfEventStream }
if let location = pt {
 let msPt:NSPoint = self.window.contentView!.convert(location, from: nil)
 print("x = \(msPt.x) : y = \(msPt.y)")
 if msPt.x < (self._wndW - self._labelW) && msPt.y < (self._wndH - self._labelH ) {
 self.here2.append(NSTextField.init())
 self.here2[self.count].frame = NSMakeRect(msPt.x, msPt.y, self._labelW, self._labelH) 
 print(self.here2[self.count].frame)
 self.window.contentView!.addSubview (self.here2[self.count])
 self.here2[self.count].backgroundColor = NSColor.white
 self.here2[self.count].isSelectable = false
 self.here2[self.count].stringValue = String(self.count)
 print("count is: " + String(self.here2.count))
 self.count+=1
}
}
  return [=10=]
 }
}

func buildMenu() {
 let mainMenu = NSMenu()
 NSApp.mainMenu = mainMenu
 // **** App menu **** //
 let appMenuItem = NSMenuItem()
 mainMenu.addItem(appMenuItem)
 let appMenu = NSMenu()
 appMenuItem.submenu = appMenu
 appMenu.addItem(withTitle: "Quit", action:#selector(NSApplication.terminate), keyEquivalent: "q") 
}

func buildWnd() {
 window = NSWindow(contentRect:NSMakeRect(0,0,_wndW,_wndH),styleMask:[.titled, .closable, .miniaturizable, .resizable], backing:.buffered, defer:false)
 window.center()
 window.title = "Swift Test Window"
 window.makeKeyAndOrderFront(window)
 window.acceptsMouseMovedEvents = true

// **** Button **** //
let myBtn = NSButton (frame:NSMakeRect( _wndW - 180, 15, 135, 24 ))
 myBtn.bezelStyle = .rounded
 myBtn.autoresizingMask = [.maxXMargin,.minYMargin]
 myBtn.title = "Start Label Maker"
 myBtn.action = #selector(self.getCoordinates(_:))
 window.contentView!.addSubview (myBtn)

// **** Quit btn **** //
let quitBtn = NSButton (frame:NSMakeRect( _wndW - 50, 10, 40, 40 ))
 quitBtn.bezelStyle = .circular
 quitBtn.autoresizingMask = [.minXMargin,.maxYMargin]
 quitBtn.title = "Q"
 quitBtn.action = #selector(NSApplication.terminate)
 window.contentView!.addSubview(quitBtn)
}

func applicationDidFinishLaunching(_ notification: Notification) {
 buildMenu()
 buildWnd()
}

func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
 return true
}

}
let appDelegate = AppDelegate()

// **** main.swift **** //
let app = NSApplication.shared
app.delegate = appDelegate
app.setActivationPolicy(.regular)
app.activate(ignoringOtherApps:true)
app.run()


您无法在故事板中连接 NSTextField 的数组。在我看来,这是 Xcode 中的错误,IB 不应建立连接。这也是 AppKit 中的一个错误,我尝试了这个并得到了这个奇怪的错误:

Failed to set (contentViewController) user defined inspected property on (NSWindow): [<__NSTimeZone 0x6040000a2280> valueForUndefinedKey:]: this class is not key value coding-compliant for the key identifier.

解决方法:去掉IB中的连接,更改

@IBOutlet var here2 = [NSTextField]()

var here2 = [NSTextField]()
@IBOutlet weak var here2TextField: NSTextField!

在 IB 中连接 here2TextField 并将 here2TextField 附加到 viewDidLoad() 中的 here2

@Marco:我发布的代码是创建应用程序的编程方法的模板(又名样板)示例。我所做的只是 copy/paste 您的函数进入模板的 AppDelegate class 并将其连接到一个按钮。从那里我修改了您的代码,直到获得所需的结果。该技术不使用 XIB 或故事板,而是要求源代码由作者编写(或使用模板)。好消息是您可以控制您的应用程序,不会有人在您背后做任何事情;你所看到的就是你得到的。缺点是该技术对于真正的大型项目来说很麻烦;为此,我依赖 Xcode 和 XIB。 Xcode 的自动完成功能也非常有用,而使用编程方法您必须依赖 Xcode/Help/DeveloperDocumentation 以及互联网搜索,尤其是 Whosebug(通常其他人遇到了与您遇到的相同问题).代替使用终端的命令行进行每次编译,我使用一个非常简单的编辑器自动化了该过程,该编辑器是使用 Xcode(使用 XIB)在 Swift 中编写的。但是,通过执行以下操作,发布的代码也可以是 Xcode 中的 运行:

1) 使用 Swift 创建一个新的 macOS 应用程序(用户界面是 XIB,但演示不需要) 2) 使用File/New/File添加一个Swift文件并命名为‘main.swift’ 3) 在新的 main.swift 文件中,将“import Foundation”更改为“import Cocoa” 4) Copy/paste 将演示的最后五行(标记为 main.swift)放入此文件 5) 进入 Apple 提供的 AppDelegate 文件,删除除“import Cocoa”之外的所有内容 6) Copy/paste 已发布代码的整个 AppDelegate class(一直到您已经使用过的 main.swift 部分) 7) 点击‘运行’按钮,编译应该没有错误。

希望对您有所帮助,祝您项目顺利。感谢发帖。