I’m wondering if someone can provide an example of using NSTokenField in ASOC… Something simple, not too complex.
For example, let’s say I have an array of items {“one”, “two”, “three”, “four”, “five”} and a simple NSWindow with only an NSTokenField that I would like to autocomplete and update from the array.
I’ve searched everywhere and I can’t seem to find any examples of this in ASOC. Plenty in ObjC, but I sometimes feel like I’m reading greek.
What exactly do you mean by autocomplete? Do you want suggestions to what you are typing based on items in the array? Like mail’s address fields?
I have done a project with token fields, but I let the user drag and drop tokens from another token field to one that’s empty… Sounds different than what you want to accomplish.
Could you give a few websites that have objective c code… Maybe I could whip up something.
Browser: Safari 6533.18.5
Operating System: Mac OS X (10.6)
I’ve just looked at the Token Field Programming guide, and it’s pretty easy actually. You need to set your delegate for your NSTokenField to an applescript class file of your choosing (I suggest creating a brand new file to keep things seperate), and use this code:
on tokenField_completionsForSubstring_indexOfToken_indexOfSelectedItem_(tokenFieldArg, substring, tokenIndex, selectedIndex)
tell current application's NSArray to set completionItems to arrayWithArray_({"one", "two", "three", "four", "five"})
tell current application's NSPredicate to set filteringPredicate to predicateWithFormat_((("SELF beginswith[cd] " & substring) as string))
tell current application's NSArray to set filteredCompletionItems to completionItems's filteredArrayUsingPredicate_(filteringPredicate)
return filteredCompletionItems
end tokenField_completionsForSubstring_indexOfToken_indexOfSelectedItem_
It’s untested, but should work.
Interestingly, you can also create a menu that will display custom items and commands to each token. This is a little bit more difficult to implement, but still feasible in ASOC.
Let me know how if it works!
Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)
Essentially yes, I would like to get an NSTokenField where you can start typing and it will suggest items from those in the array (or I could populate the tokens in the NSTokenField manually if need be). I don’t want to use it in a drag and drop manner as you describe.
Currently I’ve been using NSComboBox, but I find this limited because you can’t really select multiple items in an NSComboBox while you can have multiple items (or “tokens”/“objects”) in an NSTokenField. The whole point is to start typing and have it autofill based on what it’s being populated with.
There really aren’t many examples I’ve been able to find (even in objC).
I’ve found these (briefly), not sure if they help. Maybe others also have some examples? I think for posterity it’d be nice to have a few ASOC examples of using NSTokenField as it’s a pretty powerful class that allows for quite a bit of flexibility.
Just for the fun of it… How to implement a menu item for a token object in an NSTokenField.
You need to implement two methods in the delegate for the NSTokenField. The first one will be called by the token to find out if it should display the little triangle. This example code will always return yes, but it could be modified depending on your needs. The second method will be called by the token to get an NSMenu object to display when the user clicks on the triangle.
on tokenField_hasMenuForRepresentedObject_(tokenField, representedObject)
return true
end tokenField_hasMenuForRepresentedObject_
where tokenField is an NSTokenField object from which you can use various instance methods on. representedObject is a represented object of the token field, but I think this is inaccessible from ASOC being an id type of object. Unless someone else can tell us otherwise?
on tokenField_menuForRepresentedObject_(tokenField, representedObject)
tell current application's NSMenu to set returnMenu to alloc()'s init()
if ((representedObject's |exists|()) as boolean) is false then return missing value --this is where I fear it will bug, I believe the exists method is unaccessible from ASOC. Maybe it could be changed to something else... anyone has an idea?
--plain menu item, will be grayed out by default.
tell current application's NSMenuItem to set firstMenuItem to alloc()'s init()
firstMenuItem's setTitle_("This is an example")
tell returnMenu's |menu|() to addItem_(firstMenuItem)
--menu item with a selector
tell current application's NSMenuItem to set secondMenuItem to alloc()'s initWithTitle_action_keyEquivalent_("Do something", "doSomething:", "")
secondMenuItem's setTarget_(me)
secondMenuItem's setRepresentedObject_(representedObject) --not sure what this will do...
tell returnMenu's |menu|() to addItem_(secondMenuItem)
return returnMenu
end tokenField_menuForRepresentedObject_
This should do the trick. This is untested and I posted that for the fun of exploration and learning. If someone actually tries it and encounters problems with it, please post back for everyone to see.
Thanks!
Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)
I’ve posted some code below that I think does what stokkes wants, and fixed some of the code that leonsimard posted.
Only the applicationWillFinishLaunching and tokenField_completionsForSubstring_indexOfToken_indexOfSelectedItem methods are needed to implement the completion behavior, the other methods deal with adding menus to the tokens.
script TokensAppDelegate
property parent : class "NSObject"
property tokenField : missing value --Connected to an NSTokenField in IB
property theNames : missing value --The array holding the completion item list
on applicationWillFinishLaunching_(aNotification)
tokenField's setDelegate_(me)
set theNames to current application's NSArray's arrayWithArray_({"Pomona", "Potomac", "Potable", "Process", "Plow"})
end applicationWillFinishLaunching_
on tokenField_completionsForSubstring_indexOfToken_indexOfSelectedItem_(tokenField, substring, 0, missing value)
set matchingNames to theNames's filteredArrayUsingPredicate_(current application's NSPredicate's predicateWithFormat_("self beginswith[cd] %@", substring))
return matchingNames
end tokenField_completionsForSubstring_indexOfToken_indexOfSelectedItem_
on tokenField_hasMenuForRepresentedObject_(tokenField, representedObject)
return true
end tokenField_hasMenuForRepresentedObject_
on tokenField_menuForRepresentedObject_(tokenField, representedObject)
set returnMenu to current application's NSMenu's alloc()'s init()
returnMenu's setAutoenablesItems_(0)
set firstMenuItem to current application's NSMenuItem's alloc()'s init()
firstMenuItem's setTitle_("This is an example")
returnMenu's addItem_(firstMenuItem)
set secondMenuItem to current application's NSMenuItem's alloc()'s initWithTitle_action_keyEquivalent_("Do something", "doSomething:", "")
returnMenu's addItem_(secondMenuItem)
return returnMenu
end tokenField_menuForRepresentedObject_
on doSomething_(sender)
log "got to doSomething"
end doSomething_
end script
I picked strings that show the behavior of the completion process as the user types – the tokenField_completionsForSubstring_indexOfToken_indexOfSelectedItem method is called each time you type a letter, and the list gets filtered down.
To leonsimard: You were right about the “exists” method – it didn’t work. I’m not sure why that statement was even in the objective C example in the docs, but eliminating it seems to be ok for now. I changed a few other things. The “tell returnMenu’s |menu|() to addItem_(firstMenuItem)” statement isn’t the correct syntax --you send the addItem message directly to returnMenu, there is no |menu|() method. I haven’t dealt with the issue of representedObjects at all yet.
Ric
After Edit: I also deleted two other statements, secondMenuItem’s setTarget_(me) and secondMenuItem’s setRepresentedObject_(representedObject). Neither of them were necessary for the menus to work.
Your code rdelmar works perfectly and gives me the starting point I need to implement this kind of functionality. I also think it will act as a reference for any other potential ASOC developer looking for some concrete example of how to properly make use of NSTokenField in ASOC.
I haven’t look at all the code yet, just copy and pasted it into a new project and linked in IB to make it work… I’ll take a further look a bit later and post again…
Alright, had a chance to look at this and everything is much clearer now… I’ve learnt quite a bit based on both examples given…
I’ve figured out a way to get all the strings from objectValue., but I’m hitting a small stumbling block in using setObjectValue… I guess the syntax is escaping me
I want to setObjectValue(sender) to missing value to clear the NSTokenField…
Any pointers to the syntax of using setObjectValue?
tokenField's setObjectValue_(missing value) -- will clear the field
tokenField's setObjectValue_({"new item 1", "new item 2"} -- will set new tokens (as string only)
Glad to know that I could be of some help, if I can give back to this forum that helped me so much, I’ll try!
Yeah, missing underscores is the number one mistake that I used to do before… You’ll get over that quickly.
And can I ask for what task are you going to use this nstoken field? Its just that I havent seen it used the way you want to use it besides addresses in the mail app… Just curious to see what else it can be usefull for.
I’m using it to build a small app that will help me get organized in Outlook… I should be able to share something soon.
I actually do have another weird issue with NSTokenField that isn’t present in NSComboBox…
That is, if I put an NSTokenField in an NSPanel, when I hit “enter” to accept the token, the application receives an applicationShouldTerminate_(sender)… If I put the SAME NSTokenField into an NSWindow, this doesn’t happen
I have absolutely no idea why this is happening nor can I see anything that I may have done in IB to cause this behaviour.
Hmmm… I moved my token field to an NS panel, and I didn’t see that behavior, it still operates as normal. Maybe you should post what code you are using.
Yep, same here. Need to see some code. I just can’t see how that would be possible unless the code was written that way… especially the return key, can’t see how it would cause a terminate call to the app.
Thanks for your explanation, I’m curious to see the results!