Swift NSSearchField NSTableView Sample Code
Created By:Debasis Das (May 2016)
In this post we will discuss the most lengthy way to implement a NSSearchField and tie the same to a NSTableView.
Earlier we have discussed two alternate ways to achieve the same functionality
Approach 1 http://www.knowstack.com/swift-nssearchfield-nstableview-with-bindings/ In this article we had achieved the same functionality using bindings. This approach is the simplest and least amount of coding is required. however things becomes tricky when columns are created dynamically
Approach 2: http://www.knowstack.com/swift-nssearchfield-nsarraycontroller-no-bindings/ In this article we have used an NSArrayController to hold the backup data prior to filtering.
In Approach 3 we will implement everything through code.
// AppDelegate.swift // NSSearchField_NSTableView_Programatically // Created by Debasis Das on 27/05/16. // Copyright © 2016 Knowstack. All rights reserved. import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate, NSTableViewDelegate,NSTableViewDataSource { //The app delegate is the table view delegate and datasource @IBOutlet weak var window: NSWindow! @IBOutlet weak var tableView: NSTableView! @IBOutlet weak var searchField:NSSearchField! var contacts:[Person] = [] //The contacts array var backUpContacts:[Person] = [] //The backup array to hold the original list func applicationDidFinishLaunching(aNotification: NSNotification) { // Insert code here to initialize your application self.tableView.setDataSource(self) self.tableView.setDelegate(self) for item in self.dataArray(){ self.contacts.append(item as! Person) } self.backUpContacts = self.contacts //Creating a backup of the contacts. Ideally the backup list should be populated from the find method that fetches records from a database self.tableView.reloadData() self.createMenuForSearchField() } func createMenuForSearchField(){ let menu = NSMenu() menu.title = "Menu" let allMenuItem = NSMenuItem() allMenuItem.title = "All" allMenuItem.target = self allMenuItem.action = #selector(AppDelegate.changeSearchFieldItem(_:)) let fNameMenuItem = NSMenuItem() fNameMenuItem.title = "First Name" fNameMenuItem.target = self fNameMenuItem.action = #selector(AppDelegate.changeSearchFieldItem(_:)) let lNameMenuItem = NSMenuItem() lNameMenuItem.title = "Last Name" lNameMenuItem.target = self lNameMenuItem.action = #selector(AppDelegate.changeSearchFieldItem(_:)) menu.addItem(allMenuItem) menu.addItem(fNameMenuItem) menu.addItem(lNameMenuItem) self.searchField.searchMenuTemplate = menu self.changeSearchFieldItem(allMenuItem) } func changeSearchFieldItem(sender:AnyObject){ //Based on the Menu item selection in the search field the placeholder string is set (self.searchField.cell as? NSSearchFieldCell)?.placeholderString = sender.title } func numberOfRowsInTableView(tableView: NSTableView) -> Int { return self.contacts.count } func tableView(tableView: NSTableView, objectValueForTableColumn tableColumn: NSTableColumn?, row: Int) -> AnyObject? { let identifier = tableColumn?.identifier let str = self.contacts[row].valueForKey(identifier!) return str } func tableView(tableView: NSTableView, setObjectValue object: AnyObject?, forTableColumn tableColumn: NSTableColumn?, row: Int) { self.contacts[row].setValue(object, forKey: (tableColumn?.identifier)!) } func dataArray()->NSMutableArray{ let arr = NSMutableArray() arr.addObject(Person.createPerson("Debasis", lName: "Das")) arr.addObject(Person.createPerson("John", lName: "Doe")) arr.addObject(Person.createPerson("Jane", lName: "Doe")) return arr } func applicationWillTerminate(aNotification: NSNotification) { // Insert code here to tear down your application } override func controlTextDidChange(obj: NSNotification) { if obj.object === self.searchField{ let searchString = self.searchField.stringValue var predicate:NSPredicate = NSPredicate() if searchString.isEmpty{ self.contacts = self.backUpContacts } else{ if (self.searchField.cell as? NSSearchFieldCell)?.placeholderString == "All"{ predicate = NSPredicate(format: "firstName contains %@ OR lastName contains %@ ",searchString,searchString) } else if (self.searchField.cell as? NSSearchFieldCell)?.placeholderString == "First Name"{ predicate = NSPredicate(format: "firstName contains %@",searchString) } else if (self.searchField.cell as? NSSearchFieldCell)?.placeholderString == "Last Name"{ predicate = NSPredicate(format: "lastName contains %@",searchString) } self.contacts = (self.backUpContacts as NSArray).filteredArrayUsingPredicate(predicate) as! [Person] } self.tableView.reloadData() } } } class Person:NSObject{ var firstName:String = "" var lastName:String = "" class func createPerson(fName:String, lName:String)->Person{ let person = Person() person.firstName = fName person.lastName = lName return person } }
You can download the sample code from NSSearchField_NSTableView_Programatically
How is the search results displayed in Mail,Finder etc? Which control is used for it?
Token Field is used for the search criterias in the mail application for the search field visualization.