Mam tableView wykonane z kilku niestandardowych NSTableCellView. Niektóre widoki muszą pokazywać licznik czasu (ile czasu minęło) wraz z NSProgressIndicator.okresowo aktualizuj pole tekstowe wewnątrz NSTableCellView za pomocą timera
Stworzyłem timer (z dużym wyświetlaczem centralnym) i co 100 ms aktualizuję textView z setNeedsDisplay (lub .needsDisplay = true w swift).
Kod, który mam działa poprawnie w zwykłym widoku z NSTextField, ale nie działa, gdy pole tekstowe jest częścią NSTableCellView. Timer strzela, ale pole nie jest przerysowane.
Nie działa również, jeśli ponownie załaduję całą tabelę co 100 ms z kontrolki viewController. Ponowne wczytanie całej tabeli nie było dobrym rozwiązaniem, ponieważ wybór jest tracony co 100 ms, a użytkownik nie może już edytować (zwykłych) komórek.
W jaki sposób powinienem ponownie załadować jeden konkretny obszar tekstowy w kilku komórkach całego widoku tabeli co sekundę?
@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?
}
Czy zdarzyło ci się to zrozumieć? – Matt
Kinda. Każda komórka ma zegar (chociaż wolałbym mieć 1 zegar dla całej tabeli). W obsadzie czasowej aktualizuję objectValue pola tekstowego, zamiast ustawiania właściwości needDisplay na true. Niestandardowy formater wyświetla prawidłową ilość upływającego czasu. Jeśli masz dużą liczbę komórek wymagających aktualizacji, prawdopodobnie spowoduje to problemy z powodu dużej liczby timerów (po jednym dla każdej komórki). Nie jest to jednak możliwe w moim przypadku. YMMV. Jeden zegar zsynchronizowałby również aktualizacje, które powinny wyglądać ładniej. – user965972