Contextual menu with search result for a NSSearchField
Asked Answered
A

3

7

I would like to have a contextual menu that shows search results as text is entered in a search field. This is an image of the default mail app in OS X that does this. I know how to filter an array of strings according to the search request of the user, but I do not know how to display it this way. I am using Swift and for a Cocoa application. Any help is appreciated.

Anselm answered 29/2, 2016 at 16:29 Comment(0)
F
7

Building from the previous answer, here is a simple Swift 3 class which you can use to automatically handle recent searches. You can add it as a custom class in your storyboard, or directly. It will look like this:

enter image description here

import Cocoa

class RecentMenuSearchField: NSSearchField {

    lazy var searchesMenu: NSMenu = {

        let menu = NSMenu(title: "Recents")

        let recentTitleItem = menu.addItem(withTitle: "Recent Searches", action: nil, keyEquivalent: "")
        recentTitleItem.tag = Int(NSSearchFieldRecentsTitleMenuItemTag)

        let placeholder = menu.addItem(withTitle: "Item", action: nil, keyEquivalent: "")
        placeholder.tag = Int(NSSearchFieldRecentsMenuItemTag)

        menu.addItem( NSMenuItem.separator() )

        let clearItem = menu.addItem(withTitle: "Clear Menu", action: nil, keyEquivalent: "")
        clearItem.tag = Int(NSSearchFieldClearRecentsMenuItemTag)

        let emptyItem = menu.addItem(withTitle: "No Recent Searches", action: nil, keyEquivalent: "")
        emptyItem.tag = Int(NSSearchFieldNoRecentsMenuItemTag)

        return menu
    }()

    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        initialize()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        initialize()
    }

    //create menu
    private func initialize() {
        self.searchMenuTemplate = searchesMenu
    }
}
Furore answered 25/7, 2017 at 23:13 Comment(2)
I don't see how this answers the question. The menu shows the recent searches, it does not show the search results as asked for (see screenshot). What am I missing?Firebrat
This doesn't answer the question. Apple's implementation popups a new child window. Alternative is autocompletion. This answer is wrong because poping out a menu means the field is losing focus and key event are handled by the menu instead of the search fieldCarlicarlick
G
5

NSSearchField searchMenuTemplate (NSMenu) contains Menu Items (NSMenuItem) with specific tags used by the Search Field to populate the Menu.

The recentSearches Array here is just to pass additional String used in complement of Recents Search strings and is not required (I thought that it was to store recent search but no). NSSearchField also clear this Array when the user clears Recents Search.

You can also configure a Menu with category, more info here: Configuring a Search Menu — Apple Developer

Example:

@IBOutlet weak var search: NSSearchField!

/// Array of string containing additional recents search (custom search)
var recentSearches = [String]()

/// Search Field Recents Menu
lazy var searchesMenu: NSMenu = {

    let menu = NSMenu(title: "Recents")

    let i1 = menu.addItem(withTitle: "Recents Search", action: nil, keyEquivalent: "")
    i1.tag = Int(NSSearchFieldRecentsTitleMenuItemTag)

    let i2 = menu.addItem(withTitle: "Item", action: nil, keyEquivalent: "")
    i2.tag = Int(NSSearchFieldRecentsMenuItemTag)

    let i3 = menu.addItem(withTitle: "Clear", action: nil, keyEquivalent: "")
    i3.tag = Int(NSSearchFieldClearRecentsMenuItemTag)

    let i4 = menu.addItem(withTitle: "No Recent Search", action: nil, keyEquivalent: "")
    i4.tag = Int(NSSearchFieldNoRecentsMenuItemTag)

    return menu
}()

override func viewDidLoad() {
    super.viewDidLoad()
    recentSearches = ["Toto","Titi","Tata"]
    search.delegate = self
    search.recentSearches = recentSearches
    search.searchMenuTemplate = searchesMenu
}
Godforsaken answered 14/6, 2017 at 17:50 Comment(0)
D
0

You need to make an NSMenu Item with special tags that are placeholders so the search field knows where to put recent items, the clear action, etc.

Look at documentation for searchMenuTemplate, and the Tags : NSSearchFieldRecentsMenuItemTag etc.

Basically, make a contextual menu in IB. Drag your search field to use that menu as the searchMenuTemplate, and then populate menu items with the tags you want for clear, recent items, etc.

Delgado answered 26/11, 2016 at 19:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.