使2矛盾的方法在drawRect

问题描述:

工作我正在写一个由CGPoints组成的应用程序构建元素。我有2个按钮:makeRectanglemakeTriangle。对于建筑/绘图阶段我使用三种方法矩形和三种方法三角形里面drawRect使2矛盾的方法在drawRect

我被我的代码卡在drawRect。在if-else-statement中,每次按下按钮时,每种方法都会交换前一个元素的建筑/绘图方案。

如果我已经建立矩形,然后我点击makeTriangle按钮,我得到新的三角形,但我的长方形变成一个未连接点的三角形。

是否有解决方法或我不应该使用drawRect方法?

下面是一个SO张贴在drawRect话题:To drawRect or not to drawRect

Animation of incorrectly-drawn trapezoid and triangle

Image of correctly-drawn trapezoid and triangle

元素声明:

enum Element { 
    case point1(point: CGPoint) 
    case point2(point: CGPoint) 
    case point3(point: CGPoint) 
    case point4(point: CGPoint) 

    func coord() -> [CGPoint] {  
     switch self { 
     case .point1(let point): return [point] 
     case .point2(let point): return [point] 
     case .point3(let point): return [point] 
     case .point4(let point): return [point] 
     } 
    } 
    func buildQuadPath(path: CGMutablePath) { 
     switch self { 
     case .point1(let point): CGPathMoveToPoint(path, nil, point.x, point.y) 
     case .point2(let point): CGPathAddLineToPoint(path, nil, point.x, point.y) 
     case .point3(let point): CGPathAddLineToPoint(path, nil, point.x, point.y) 
     case .point4(let point): CGPathAddLineToPoint(path, nil, point.x, point.y) 
     CGPathCloseSubpath(path) 
     } 
    } 
    func buildTriPath(path: CGMutablePath) { 
     switch self { 
     case .point1(let point): CGPathMoveToPoint(path, nil, point.x, point.y) 
     case .point2(let point): CGPathAddLineToPoint(path, nil, point.x, point.y) 
     case .point3(let point): CGPathAddLineToPoint(path, nil, point.x, point.y) 
     default: 
     CGPathCloseSubpath(path) 
     } 
    } 
} 

方法构建和绘制三角形和矩形:

func buildTriPath() -> CGMutablePath { 
    let path = CGPathCreateMutable() 
    _ = array.map { $0.buildTriPath(path) } 
    return path 
} 
func drawTriPath() { 
    let path = buildTriPath() 
    GraphicsState { 
     CGContextAddPath(self.currentContext, path) 
     CGContextStrokePath(self.currentContext) 
    } 
} 
func drawTriFill() { 
    let fill = buildTriPath() 
    GraphicsState { 
     CGContextAddPath(self.currentContext, fill) 
     CGContextFillPath(self.currentContext) 
    } 
} 

///////////////////////// //////////

func buildQuadPath() -> CGMutablePath { 
    let path = CGPathCreateMutable() 
    _ = array.map { $0.buildQuadPath(path) } 
    return path 
} 
func drawQuadPath() { 
    let path = buildQuadPath() 
    GraphicsState { 
     CGContextAddPath(self.currentContext, path) 
     CGContextStrokePath(self.currentContext) 
    } 
} 
func drawQuadFill() { 
    let fill = buildQuadPath() 
    GraphicsState { 
     CGContextAddPath(self.currentContext, fill) 
     CGContextFillPath(self.currentContext) 
    } 
} 

两个变量帮助确定按钮是否被按下:

var squareB: Int = 0 
var triangleB: Int = 0 

@IBAction func makeTriangle(sender: AnyObject?) { 
    .................... 
    .................... 
    triangleB += 1 
    squareB = 0 
} 
@IBAction func makeRectangle(sender: AnyObject?) { 
    .................... 
    .................... 
    triangleB = 0 
    squareB += 1 
} 

drawRect方法:

override func drawRect(dirtyRect: NSRect) { 
    super.drawRect(dirtyRect) 

    drawBG() 
    GraphicsState { self.drawMyPoints() } 

    if squareB >= 1 && triangleB == 0 { 
     buildQuadPath() 
     drawQuadPath() 
     drawQuadFill() 
     needsDisplay = true 
    } 
    else if triangleB >= 1 && squareB == 0 { 
     buildTriPath() 
     drawTriPath() 
     drawTriFill() 
     needsDisplay = true 
    } 
    drawBorder() 
} 

...,最后一个Context.swift file:

import Cocoa 
import CoreGraphics 

extension NSView { 

    var currentContext : CGContext? { 

     get { 

      let unsafeContextPointer = NSGraphicsContext.currentContext()?.graphicsPort 

      if let contextPointer = unsafeContextPointer { 
      let opaquePointer = COpaquePointer(contextPointer) 
      let context: CGContextRef = Unmanaged.fromOpaque(opaquePointer).takeUnretainedValue() 
      return context } 
      else { return nil } 
     } 
    } 

    func GraphicsState(drawStuff:() -> Void) { 
     CGContextSaveGState(currentContext) 
     drawStuff() 
     CGContextRestoreGState(currentContext) 
    } 
} 

//the end of code 
+1

您的声明与提供的代码结合起来没有任何意义。如果我弄明白了,你的默认状态是0.如果你按下一个按钮(我猜你已经启用了某种点击监听器),状态变为1.所以只应绘制两个选项中的一个。如果默认状态已正确初始化为0,并且在绘制之后(或新绘图之前)将其更改回0,请检查您的代码。 – InDaPond

+1

你必须用更多的代码支持我们。现在的代码的方式,只有一个有效的状态应绘制,并且methos的顺序没有区别,因此它们是条件块 – InDaPond

+0

你可以告诉我在GitHub中的代码。亨达我在我的文章贴'buildQuadPath'节真的不明白'buildQuadPath() drawQuadPath() drawQuadFill()' –

好的,因为我可以使用练习,我创建了一个example project来显示我的意思是vikingosegundo。

下面是它的要点:
在这个例子中我一直在所有相关的代码,除了添加和形状在GHShapeDemoView移除。 我用结构来定义形状,而是把它们作为一个是拉延过程中处理的数据的“单元”,从而增加了视图等所有形状都被保持在一个阵列,并且在绘制被重复和找到的所有形状使用简单的NSBezierPath绘制。

为了简便起见,我只是选择了一些随机的固定点,每个形状,这将明显地以另一种方式来确定一个真正的项目(我才懒得添加输入字段...)。

即使在这里有很多的方式来重构(可能)。例如,甚至可以让每个形状都成为它自己的一个类(或者通常使用一个类来表示形状)。也许甚至是NSView的一个子类,这会导致“绘图区域”本身不是一个自定义视图,而是一个普通的视图,并且按钮按下相关的形状视图将被添加为子视图。那么大概也会摆脱所有这些点 - 计算的东西(主要是)。 在一个真实的项目中,我可能会将图形作为图层子类添加到子视图中。我不是专家,但我认为这可能会带来性能上的好处,具体取决于有多少形状以及我是否将其制作为动画。 (很显然,使用OpenGL ES或某些东西可能会获得最高的性能,但我不知道这一点,这远远超出了这个问题的范围)。

我希望这提供了一个很好的起点,在你的绘图工作。如上所述,我强烈建议以类似的方式重构您的项目,以正确定义您绘制的内容以及绘制方式。如果您不知何故必须依靠将枚举点数据保存在枚举或结构体中,请将足够的映射器写入您的绘图数据结构。

+0

谢谢。我会看一看。 – andy

+0

这是行不通的。 – andy

+0

我会在10个小时内奖励赏金。 – andy

if (makeTriangle != nil) {if (makeRectangle != nil) {犯规太大的意义。根据你的评论,makerRectanglemakeTriangle是按钮。通过你的陈述,你正在检查它们的存在 - 并且我们可以假设它们总是存在 - 第一个if-子句将总是被执行。

你想要的是:创建将由按钮执行的方法。每种方法都会设置bool值的组合或单个枚举值,然后通过调用setNeedsDisplay()来告诉视图重绘。

+0

我是否必须使用标签或在此处无用? – andy

+2

标签几乎总是没用。 – vikingosegundo

下面是Gero写的代码:

此代码的工作以及与雨燕2.2。

// 
// GHShapeDemoView.swift 
// GHShapeDrawingExample 
// 
// Created by Gero Herkenrath on 21/10/2016. 
// Copyright © 2016 Gero Herkenrath. All rights reserved. 
// 

import Cocoa 

class GHShapeDemoView: NSView { 

    struct Shape { 

     var p1:CGPoint = NSMakePoint(0.0, 0.0) 
     var p2:CGPoint = NSMakePoint(0.0, 0.0) 
     var p3:CGPoint = NSMakePoint(0.0, 0.0) 
     var p4:CGPoint? 
    } 

    var shapes:[Shape] = [] 

    override internal var flipped: Bool { 
     return true 
    } 

    override func drawRect(dirtyRect: NSRect) { 
     super.drawRect(dirtyRect) 

     NSColor.whiteColor().setFill() 
     let updatedRect = NSBezierPath.init(rect: dirtyRect) 
     updatedRect.fill() 

     for shape in shapes { 
      drawShape(shape) 
     } 
    } 

    func drawShape(shape:Shape) { 
     let shapePath = NSBezierPath() 
     shapePath.moveToPoint(shape.p1) 
     shapePath.lineToPoint(shape.p2) 
     shapePath.lineToPoint(shape.p3) 

     if let lastPoint = shape.p4 { 
      shapePath.lineToPoint(lastPoint) 
     } 

     shapePath.closePath() 
     NSColor.blackColor().setStroke() 
     shapePath.stroke() 
    } 

    func addTrapezoid(p1:NSPoint, p2:NSPoint, p3:NSPoint, p4:NSPoint) { 
     var shape = Shape() 
     shape.p1 = p1 
     shape.p2 = p2 
     shape.p3 = p3 
     shape.p4 = p4 
     shapes.append(shape) 
    } 

    func addTriangle(p1:NSPoint, p2:NSPoint, p3:NSPoint) { 
     var shape = Shape() 
     shape.p1 = p1 
     shape.p2 = p2 
     shape.p3 = p3 
     shapes.append(shape) 
    } 

    func removeShapeAt(index:Int) { 
     if index < shapes.count { 
      shapes.removeAtIndex(index) 
     } 
    } 
} 

/////////////////////// //////

// 
// ViewController.swift 
// GHShapeDrawingExample 
// 
// Created by Gero Herkenrath on 21/10/2016. 
// Copyright © 2016 Gero Herkenrath. All rights reserved. 
// 

import Cocoa 

class ViewController: NSViewController { 

    override func viewDidLoad() { 

     if #available(OSX 10.10, *) { 
      super.viewDidLoad() 
     } 
     else { 
      // Fallback on earlier versions 
     } 
     // Do any additional setup after loading the view. 
    } 

    override var representedObject: AnyObject? { 
     didSet { 
     // Update the view, if already loaded. 
     } 
    } 

    // first Shape 
    let pointA1 = NSMakePoint(115.0, 10.0) 
    let pointA2 = NSMakePoint(140.0, 10.0) 
    let pointA3 = NSMakePoint(150.0, 40.0) 
    let pointA4 = NSMakePoint(110.0, 40.0) 

    // second Shape 
    let pointB1 = NSMakePoint(230.0, 10.0) 
    let pointB2 = NSMakePoint(260.0, 40.0) 
    let pointB3 = NSMakePoint(200.0, 40.0) 

    // thirdShape 
    let pointC1 = NSMakePoint(115.0, 110.0) 
    let pointC2 = NSMakePoint(140.0, 110.0) 
    let pointC3 = NSMakePoint(150.0, 140.0) 
    let pointC4 = NSMakePoint(110.0, 140.0) 


    @IBOutlet weak var shapeHolderView: GHShapeDemoView! 

    @IBAction func newTrapezoid(sender: AnyObject) { 

     if shapeHolderView.shapes.count < 1 { 
      shapeHolderView.addTrapezoid(pointA1, p2: pointA2, p3: pointA3, p4: pointA4) 
     } 
     else { 
     shapeHolderView.addTrapezoid(pointC1, p2: pointC2, p3: pointC3, p4: pointC4) 
     } 
    shapeHolderView.setNeedsDisplayInRect(shapeHolderView.bounds) 
    } 

    @IBAction func newTriangle(sender: AnyObject) { 
     shapeHolderView.addTriangle(pointB1, p2: pointB2, p3: pointB3) 
     shapeHolderView.setNeedsDisplayInRect(shapeHolderView.bounds) 
    } 

    @IBAction func removeLastShape(sender: AnyObject) { 
     if shapeHolderView.shapes.count > 0 { 
      shapeHolderView.removeShapeAt(shapeHolderView.shapes.count - 1) 
      shapeHolderView.setNeedsDisplayInRect(shapeHolderView.bounds) 
     } 
    } 
}