I'm trying to display an image in a table view cell view on the condition of a Boolean value.
The Boolean is a representation of the state of an object of the class "Book" where the objects are initialized:
class Book: NSObject, Codable {
@objc dynamic var author: String
@objc dynamic var title: String
@objc dynamic var lentBy: String
@objc dynamic var available: Bool {
if lentBy == "" {
return true
} else {return false}
}
init(author: String, title: String, lentBy: String) {
self.author = author
self.title = title
self.lentBy = lentBy
}
}
If the String lentBy
is not specified, the Bool available
returns true: no one has lent the book and hence it should be available. Binding the available
object to the table view, the respective table view cell displays either 1 or 0. Instead of 1 or 0 I would like it to display an image: NSStatusAvailable
or NSStatusUnavailable
.
Have a look at this: https://i.sstatic.net/fbsjO.png. Where the text field "Geliehen von" (lent by) is empty, the status is 1 and should display the green circle; otherwise a red circle. The green circle you see now is simply dragged into the table cell view and is non-functional. But this is the idea.
Now I'm wondering how to display the respective image view instead of the Bool 1 or 0.
The table view is constructed with the interface builder in a storyboard. If I'm trying to make changes to it programmatically, nothing gets display in the table view anymore. I suppose this is due to the set bindings. Removing the bindings just for the last column doesn't work. This is how I tried it (without implementation of the image view; I don't know how to do that programmatically):
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if tableColumn == tableView.tableColumns[2] {
let cellIdentifier = "statusCellID"
let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: cellIdentifier), owner: self) as? NSTextField
if let cell = cell {
cell.identifier = NSUserInterfaceItemIdentifier(rawValue: cellIdentifier)
cell.stringValue = books[row].lentBy
}
return cell
}
return nil
}
What's the best solution to achieve this? Could I somehow, instead of a Bool, directly return the respective, e.g. CGImage types for lentBy
s representation available
?
You are using Cocoa Bindings. This makes it very easy.
NSTableCellView
with image view into the last column and delete the current one.Rather than viewForColumn:Row
implement
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
return books[row]
}
Extend the model with an image
property which is driven by KVO
class Book: NSObject, Codable {
@objc dynamic var author: String
@objc dynamic var title: String
@objc dynamic var lentBy: String
@objc dynamic var available: Bool {
return lentBy.isEmpty
}
@objc dynamic var image: NSImage {
return NSImage(named: (lentBy.isEmpty) ? NSImage.statusAvailableName : NSImage.statusUnavailableName)!
}
static func keyPathsForValuesAffectingImage() -> Set<String> { return ["lentBy"] }
init(author: String, title: String, lentBy: String) {
self.author = author
self.title = title
self.lentBy = lentBy
}
}
In Interface Builder bind the Value
of the image view of the table cell view to Table Cell View
> objectValue.image