簡體   English   中英

使用更新的數據連續重繪路徑

[英]Continuously Redrawing a Path with Updated Data

我正在開發一個音頻可視化器 MacOS 應用程序,我想使用 Quartz/CoreGraphics 來渲染與播放音頻協調的時變頻譜。 我的渲染器代碼是:

import Cocoa

類渲染器:NSView {

override func draw(_ dirtyRect: NSRect) {
    super.draw(dirtyRect)
    NSColor.white.setFill()
    bounds.fill()
    
    guard let context = NSGraphicsContext.current?.cgContext else {return}

    var x : CGFloat = 0.0
    var y : CGFloat = 0.0

    context.beginPath()
    context.move(to: CGPoint(x: x, y: y))

    for bin in 0 ..< 300 {
        x = CGFloat(bin)
        y = CGFloat(Global.spectrum[bin])
        context.addLine(to: CGPoint(x: x, y: y))
    }
    
    context.setStrokeColor(CGColor( red: 1, green: 0, blue: 0, alpha: 1))
    context.setLineWidth(1.0)
    context.strokePath()

    self.setNeedsDisplay(dirtyRect)
}

}

這將繪制一次路徑 - 使用頻譜 [] 數組的初始全零值 - 然后無限期地繼續繪制相同的全零線。 它不會使用頻譜 [] 數組中的新值進行更新。 我使用了 print() 語句來驗證值本身是否正在更新,但 draw 函數不會使用更新后的光譜值重新繪制路徑。 我究竟做錯了什么?

下面的演示展示了如何使用由一個單獨的類中的計時器創建的隨機數來更新 NSView 以模擬您的項目。 它可以通過為 MacOS 設置一個 Swift 項目,將源代碼復制/粘貼到名為“main.swift”的新文件中,並刪除 Apple 提供的 AppDelegate 來在 Xcode 中運行。 使用類似於您發布的繪圖功能。

import Cocoa

var view : NSView!
var data = [Int]()

public extension Array where Element == Int {
    static func generateRandom(size: Int) -> [Int] {
        guard size > 0 else {
            return [Int]()
        }
        return Array(0..<size).shuffled()
    }
}

class DataManager: NSObject {
var timer:Timer!

@objc func fireTimer() {
data = Array.generateRandom(size:500)
view.needsDisplay = true
}

func startTimer(){
timer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(fireTimer), userInfo: nil, repeats: true)
}

func stopTimer() {
 timer?.invalidate()
}

}
let dataMgr = DataManager()

class View: NSView {

override func draw(_ rect: NSRect) {
 super.draw(rect)
 NSColor.white.setFill()
 bounds.fill()
    
 guard let gc = NSGraphicsContext.current?.cgContext else {return}

  var xOld : CGFloat = 0.0
  var yOld : CGFloat = 0.0
  var xNew : CGFloat = 0.0
  var yNew : CGFloat = 0.0
  var counter : Int = 0

  gc.beginPath()
  gc.move(to: CGPoint(x: xOld, y: yOld))

  for i in 0 ..< data.count {
    xNew = CGFloat(counter)
    yNew = CGFloat(data[i])
    gc.addLine(to: CGPoint(x: xNew, y: yNew))
    xOld = xNew;
    yOld = yNew;
    counter = counter + 1
  }
    
  gc.setStrokeColor(CGColor( red: 1, green: 0, blue: 0, alpha: 1))
  gc.setLineWidth(1.0)
  gc.strokePath()
}

}

class ApplicationDelegate: NSObject, NSApplicationDelegate {
 var window: NSWindow!

@objc func myStartAction(_ sender:AnyObject ) {
  dataMgr.startTimer()
}

@objc func myStopAction(_ sender:AnyObject ) {
  dataMgr.stopTimer()
}

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

data = Array.generateRandom(size: 500)

 let _wndW : CGFloat = 800
 let _wndH : CGFloat = 600

 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)

// **** Start Button **** //
 let startBtn = NSButton (frame:NSMakeRect( 30, 20, 95, 30 ))
 startBtn.bezelStyle = .rounded
 startBtn.title = "Start"
 startBtn.action = #selector(self.myStartAction(_:))
 window.contentView!.addSubview (startBtn)

// **** Stop Button **** //
 let stopBtn = NSButton (frame:NSMakeRect( 230, 20, 95, 30 ))
 stopBtn.bezelStyle = .rounded
 stopBtn.title = "Stop"
 stopBtn.action = #selector(self.myStopAction(_:))
 window.contentView!.addSubview (stopBtn)

// **** Custom view **** //
 view = View( frame:NSMakeRect(20, 60, _wndW - 40, _wndH - 80)) 
 view.autoresizingMask = [.width, .height]      
 window.contentView!.addSubview (view)
    
// **** 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 applicationDelegate = ApplicationDelegate()

// **** main.swift **** //
let application = NSApplication.shared
application.setActivationPolicy(NSApplication.ActivationPolicy.regular)
application.delegate = applicationDelegate
application.activate(ignoringOtherApps:true)
application.run()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM