Search code examples
cocoanstokenfield

Updating NSTokenField after changing content programmatically


I have implemented a NSTokenField which uses some custom data objects for display of dynamic data. Delegate is set up fine and displays the correct values of the token.

I've also implemented a menu on the tokens which allows selection of the format used for display of each token. My problem is however that I'm unable to make the NSTokenField respond immediately to these changes and redraw the token with the newly selected format.

If I click outside of the NSTokenField so it resigns first responder it redraws immediately. I can also do this programmatically by explicitly setting first responder to nil. The only problem with this is that the NSTokenField looses focus - and reassigning it as first responder selects everything in the field so the user may accidentally overwrite the entire content.

So my question is whether there are any way of just triggering the NSTokenField to redraw its content without changing focus and selection?


Solution

  • I had the same problem and found the only workable solution was to "reset" the token field every time its contents changed. Basically this boiled down to running the following method of the view controller that handled the view with the token field:

    - (void) resetTokenField {
    
        // Force the token field to redraw itself by resetting the represented object.
    
        id anObject = [self representedObject];
        [self setRepresentedObject: nil];
        [self setRepresentedObject: anObject];
        [[self tokenField] setNeedsDisplay: YES];
    
    }
    

    The represented object is the object that holds all the tokens that are being displayed. In my case that was a chunk of richt text where tokens are basically tags.

    I found NSTokenField to be a royal pain in the neck but persevered as I quite like the presentation side of it.

    EDIT: My token field was bound to the tagsAsArray method of the represented object of the view controller. So basically I used Cocoa bindings to solve the problem.