gpt4 book ai didi

swift - 使用 Cocoa for OS X、Xcode 9.3、Swift 4.1 复制 View 问题

转载 作者:行者123 更新时间:2023-11-30 11:31:57 26 4
gpt4 key购买 nike

我是编程新手,正在尝试使用 Xcode 9.3 和 Swift 4.1 学习 Mac OS 的 Cocoa。我读过有关 C++ 和 Objective-C 的书籍。现在我正在阅读 Big Nerd Ranch 的书《Mac OS 的 Cocoa 编程》第 5 版,该书使用 Swift 2.0(我自己)。试图解决 Swift 2.0 到 4.1 之间的差异时遇到了一些挑战,我不知道这个问题是否是其中的一部分。

为了总结练习,我创建了一个骰子。练习的一部分是通过双击骰子来改变骰子的编号。我这样做了,而且成功了。现在我需要将骰子复制两次,总共三个骰子。

我按照步骤复制了骰子(突出显示 dieView 和 command-D),现在我有了三个骰子。每个 View 都接受第一响应者,并且每个 View 随后接受键盘输入以更改骰子上显示的数字。我可以用鼠标选择关键窗口,并且突出显示哪个窗口处于事件状态。然而,双击“掷”骰子仅适用于原始骰子,不适用于其他两个。当它们完全重复时怎么可能呢?既然它们被复制了,我怎样才能让双击在其他两个骰子中工作,因为它们应该具有相同的代码?

我还尝试将原始骰子移动到第三个位置,将两个新骰子移过来,现在双击时仍然是第一个位置的骰子,而不是最后两个骰子。当我将骰子移动到堆叠位置时,一个在另一个之上,一个在另一个之上,一开始我将它们放在窗口的左侧,并且双击对其中任何一个都不起作用。我调整了窗口大小,使它们全部堆叠在左侧,并且双击仅适用于底部芯片。

我知道这与骰子所在的自定义 View 窗口有关,但鼠标单击不应该在该窗口中的任何位置注册吗?显然,点击次数已被记录,因为我可以将关键窗口更改为每个骰子。只是双击功能无法正常工作。

这是我的 dieView 代码:

import Cocoa

@IBDesignable class DieView: NSView {

var intValue: Int? = 1 {
didSet {
needsDisplay = true
}
}

var pressed: Bool = false {
didSet {
needsDisplay = true
}
}

var dieShape = NSBezierPath()

override var intrinsicContentSize: NSSize {
return NSSize(width: 20, height: 20)
}

override func draw(_ dirtyRect: NSRect) {
let backgroundColor = NSColor.lightGray
backgroundColor.set()
NSBezierPath.fill(bounds)
drawDieWithSize(size: bounds.size)
}

func metricsForSize(size: CGSize) -> (edgeLength: CGFloat, dieFrame: CGRect) {
let edgeLength = min(size.width, size.height)
let padding = edgeLength/10.0
let drawingBounds = CGRect(x: 0, y: 0, width: edgeLength, height: edgeLength)
var dieFrame = drawingBounds.insetBy(dx: padding, dy: padding)
if pressed {
dieFrame = dieFrame.offsetBy(dx: 0, dy: -edgeLength/40)
}
return (edgeLength, dieFrame)
}

func drawDieWithSize(size: CGSize) {
if let intValue = intValue {
let (edgeLength, dieFrame) = metricsForSize(size: size)
let cornerRadius: CGFloat = edgeLength/5.0
let dotRadius = edgeLength/12.0
let dotFrame = dieFrame.insetBy(dx: dotRadius * 2.5, dy: dotRadius * 2.5)

// The glint must be within the dot.
let glintFrame = dotFrame

NSGraphicsContext.saveGraphicsState()

let shadow = NSShadow()
shadow.shadowOffset = NSSize(width: 0, height: -1)
//shadow.shadowBlurRadius = edgeLength/20
shadow.shadowBlurRadius = (pressed ? edgeLength/100 : edgeLength/20)
shadow.set()

// Draw the rounded shape of the die profile:
// Challenge use color Gradient - commented portions are used to make white die and were removed to make code more readable in this post
let gradient = NSGradient(starting: NSColor.red, ending: NSColor.blue)
dieShape =
NSBezierPath(roundedRect: dieFrame, xRadius: cornerRadius, yRadius: cornerRadius)
gradient?.draw(in: dieShape, angle: 1.0)

// Challlenge - use stroke() to add a border the die
NSColor.black.set()
dieShape.lineWidth = 4
dieShape.stroke()

NSGraphicsContext.restoreGraphicsState()
// Shadow will not apply to subequent drawing commands

// ready to draw the dots.
// Nested Function to make drawing dots cleaner:
func drawDot(u: CGFloat, v: CGFloat) {
let dotOrigin = CGPoint(x: dotFrame.minX + dotFrame.width * u,
y: dotFrame.minY + dotFrame.height * v)
let dotRect =
CGRect(origin: dotOrigin, size: CGSize.zero).insetBy(dx: -dotRadius, dy: -dotRadius)
// The dots will be black:
NSColor.black.set()
NSBezierPath(ovalIn: dotRect).fill()
}


// nested function to draw a glint in each dot
func drawGlint(u: CGFloat, v: CGFloat) {
let glintOrigin = CGPoint(x: glintFrame.minX + glintFrame.width * u,
y: glintFrame.minY + glintFrame.height * v)
let glintRect =
CGRect(origin: glintOrigin,
size: CGSize(width: 3.5, height: 3.5)).insetBy(dx: -0.5, dy: -0.5)

// Glints will be white
NSColor.white.set()
NSBezierPath(rect: glintRect).fill()
}

// If intVlaue is in range...
if intValue >= 1 && intValue <= 6 {
// Draw the dots:
if intValue == 1 || intValue == 3 || intValue == 5 {
drawDot(u: 0.5, v: 0.5) // Center dot
drawGlint(u: 0.55, v: 0.55)
}
if intValue >= 2 && intValue <= 6 {
drawDot(u: 0, v: 1) // upper left
drawGlint(u: 0.05, v: 1.05)
drawDot(u: 1, v: 0) // Lower right
drawGlint(u: 1.05, v: 0.05)
}
if intValue >= 4 && intValue <= 6 {
drawDot(u: 1, v: 1) // Upper right
drawGlint(u: 1.05, v: 1.05)
drawDot(u: 0, v: 0) // lower left
drawGlint(u: 0.05, v: 0.05)
}
if intValue == 6 {
drawDot(u: 0, v: 0.5) // Mid left/right
drawGlint(u: 0.05, v: 0.55)
drawDot(u: 1, v: 0.5)
drawGlint(u: 1.05, v: 0.55)
}
} else {
let paraStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
paraStyle.alignment = .center
let font = NSFont.systemFont(ofSize: edgeLength * 0.5)
let attrs = [NSAttributedStringKey.foregroundColor: NSColor.black,
NSAttributedStringKey.font : font,
NSAttributedStringKey.paragraphStyle: paraStyle ]
let string = "\(intValue)" as NSString
string.drawCentered(in: dieFrame, attributes: attrs)

}
}
}

func randomize() {
intValue = Int(arc4random_uniform(5)) + 1
}

// MARK: - Mouse Events

override func mouseDown(with event: NSEvent) {
if dieShape.contains(event.locationInWindow) {
Swift.print("mouseDown CLICKCOUNT: \(event.clickCount)")
let dieFrame = metricsForSize(size: bounds.size).dieFrame
let pointInView = convert(event.locationInWindow, from: nil)
pressed = dieFrame.contains(pointInView)
}
}

override func mouseDragged(with event: NSEvent) {
Swift.print("mouseDragged")
}

override func mouseUp(with event: NSEvent) {
if dieShape.contains(event.locationInWindow) {
Swift.print("mouseUp clickCount: \(event.clickCount)")
if event.clickCount == 2 {
randomize()
}
pressed = false
}
}

// MARK: - First Responder

override func drawFocusRingMask() {
NSBezierPath.fill(bounds)
}

override var focusRingMaskBounds: NSRect {
return bounds
}

override var acceptsFirstResponder: Bool { return true }

override func becomeFirstResponder() -> Bool {
return true
}

override func resignFirstResponder() -> Bool {
return true
}

// MARK: Ketboard Events

override func keyDown(with event: NSEvent) {
interpretKeyEvents([event])
}

override func insertText(_ insertString: Any) {
let text = insertString as! String
if let number = Int(text) {
intValue = number
}
}

override func insertTab(_ sender: Any?) {
window?.selectNextKeyView(sender)
}

override func insertBacktab(_ sender: Any?) {
window?.selectPreviousKeyView(sender)
}
}

最佳答案

快速浏览一下后,我猜测问题出在 if dieShape.contains(event.locationInWindow) 中。

diaShape 位于局部( View )坐标中。但 event.locationInWindow 位于窗口坐标中。您需要先将窗口坐标转换为本地坐标,然后才能测试命中点。

请参阅 locationInWindow 的文档:

let eventLocation = event.locationInWindow
let localPoint = self.convert(eventLocation, from: nil)
if dieShape.contains(localPoint)
...

如果您的 View 靠近窗口的原点,则窗口和 View 坐标之间的差异足够小,它可能会起作用,但距离较远的 View 则不会。

关于swift - 使用 Cocoa for OS X、Xcode 9.3、Swift 4.1 复制 View 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50165434/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com