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

Posted

技术标签:

【中文标题】在单击 SWIFT 的位置添加新标签【英文标题】:Adding a new label where clicked SWIFT 【发布时间】:2020-05-30 15:37:21 【问题描述】:

我想为一个 MacOS 应用程序编写一个简单的 swift 代码,它可以在用户在窗口中执行鼠标点击的任何位置添加一个新标签。

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

@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 $0
    

【问题讨论】:

“但是让应用崩溃”,好吧,那么错误信息是什么? 无法在 (NSWindow) 上设置 (contentViewController) 用户定义的检查属性:-[NSTextField copyWithZone:]:无法识别的选择器发送到实例 0x100724e30 题外话,维护一个类属性count只会使事情复杂化,而当您需要它时,只需使用数组上的.count属性 应用什么时候崩溃?从哪里调用getCoordinateshere2 是否在情节提要中连接? 我是 swift 新手,所以也许这是一个愚蠢的观察,但我认为当我将数组 [NSTextField] 连接到情节提要中的“简单”NSTextField 对象时,问题就开始了。出于我的目的,我需要使用数组,因为我不知道应该在 ViewController 中添加多少 NSTextField ......这是我问题的全部问题 【参考方案1】:

这是一种可以在终端中运行的程序化方法。请注意,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 $0
 


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


【讨论】:

谢谢@apodidae!该代码非常有用,而且效果很好!现在我应该将此代码集成到我的应用程序中,该应用程序是使用 XCode 作为单视图应用程序和情节提要完成的......我该怎么做?也许我可以完全重写应用程序以便在终端上运行......你知道我在哪里可以学习这种不同的方法(书籍?其他资源?)?【参考方案2】:

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

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

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

【讨论】:

【参考方案3】:

您无法在情节提要中连接和排列NSTextField。在我看来,这是 Xcode 中的一个错误,IB 不应该建立连接。这也是 AppKit 中的一个错误,我尝试了这个并得到了这个奇怪的错误:

无法在 (NSWindow) 上设置 (contentViewController) 用户定义的检查属性:[<__nstimezone> valueForUndefinedKey:]:此类不符合键标识符的键值编码。

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

@IBOutlet var here2 = [NSTextField]()

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

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

【讨论】:

【参考方案4】:

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

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

希望它对您的项目有所帮助并祝您好运。感谢发帖。

【讨论】:

以上是关于在单击 SWIFT 的位置添加新标签的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中的 UITableViewCell 上添加带有单击事件的按钮?

我们如何在 Swift 中单击第一个 VC 时打开标签栏

创建一个viewcontroller并将现有VC的标签和按钮添加到新的VC Swift iOS

在 Swift 3 中单击标签栏项目时从底部打开弹出窗口?

Swift:单击后退按钮后错过标签栏

Swift UICollectionView 在单击时更新单元格标签而不是实时更新