Ho una tabellaView composta da diversi NSTableCellView personalizzati. Alcune delle viste devono mostrare un timer (quanto tempo è trascorso) insieme a NSProgressIndicator.aggiorna periodicamente il campo di testo all'interno di NSTableCellView con un timer
Ho creato un timer (con display centrale grand) e ogni 100 ms aggiorno il testoView con setNeedsDisplay (o .needsDisplay = true in swift).
Il codice che ho funziona correttamente in una vista normale con un NSTextField, ma non funziona una volta che il campo di testo è parte di un NSTableCellView. Il timer scatta ma il campo non viene ridisegnato.
Non funziona anche se ricarico l'intera tabella ogni 100 ms all'interno di viewController. Ricaricare l'intera tabella non è stata comunque una buona soluzione perché la selezione viene persa ogni 100 ms e l'utente non può più modificare le celle (regolari).
Quindi, come dovrei ricaricare un determinato campo di testo in poche celle di un'intera tableview ogni secondo?
@IBDesignable class ProgressCellView : NSTableCellView
{
//MARK: properties
@IBInspectable var clock : Bool = false //should this type of cell show a clock? (is set to true in interface builder)
private lazy var formatter = TimeIntervalFormatter() //move to view controller?: 1 timer for the entire table => but then selection is lost
private var timer : dispatch_source_t!
private var isRunning : Bool = false
//MARK: init
override func awakeFromNib()
{
self.timeIndex?.formatter = formatter
if self.clock
{
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue())
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 0), 100 * NSEC_PER_MSEC, 50 * NSEC_PER_MSEC) //50 ms leeway, is good enough for the human eye
dispatch_source_set_event_handler(timer) {
self.timeIndex?.needsDisplay = true
//self.needsDisplay = true
//self.superview?.needsDisplay = true
}
}
}
//only run the clock when the view is visible
override func viewWillMoveToSuperview(newSuperview: NSView?)
{
super.viewWillMoveToSuperview(newSuperview)
if self.clock && !isRunning { dispatch_resume(self.timer); isRunning = true }
}
override func removeFromSuperview()
{
super.removeFromSuperview()
if self.clock && isRunning { dispatch_suspend(self.timer); isRunning = false }
}
//MARK: properties
override var objectValue: AnyObject? {
didSet {
let entry = self.objectValue as! MyEntry
self.progressBar?.doubleValue = entry.progress?.fractionCompleted ?? 0
self.timeIndex?.objectValue = entry.dateStarted
}
}
//MARK: user interface
@IBOutlet var timeIndex : NSTextField?
@IBOutlet var progressBar : NSProgressIndicator?
}
Hai mai capito questo? – Matt
Kinda. Ogni cella ha un timer (anche se preferirei avere 1 timer per l'intera tabella). Nel gestore del timer aggiorno il valore objectValue del campo di testo, invece di impostare needsDisplay su true. Un formattatore personalizzato mostra la quantità corretta di tempo trascorso. Se si dispone di un numero elevato di celle che devono essere aggiornate, ciò probabilmente causerà problemi a causa dell'elevato numero di timer (uno per ogni cella). Non è previsto nel mio caso, però. YMMV. Un timer sincronizzerebbe anche gli aggiornamenti, che dovrebbero apparire più belli. – user965972