NSTableView allow selection change without becoming first responder - macos

I've a window with a split view. Left is a NSTableView, to the right a custom view.
When my custom view is active in a 'command mode' I need it to remain first responder status so it can receive a cancelOperation: event when the escape key is pressed. But I do want the user to be able to change the selection in the table view.
Unfortunately, as long as my custom view refuses to resign first responder status the table view doesn't respond.
How can I make sure that the table view allows changing the selection without becoming first responder? Or how can I make sure the cancelOperation: event is delivered to my custom view, while it's not first responder?

the table view allows changing the selection without becoming first responder
Don't do this. It will confuse the user. The table view should become first responder.
Or how can I make sure the cancelOperation: event is delivered to my custom view, while it's not first responder
Put Cancel button in the window with key equivalent Escape. Or if you don't want a button, let an object in the responder chain (view controller, window controller) catch the escape key by implementing cancel: and tell the custom view to cancel.

Related

How to get notified of clicks in a view-based NSTableView

I have a view-based NSTableView containing a list of words. When the user double-clicks on a word, I would like to take an action. The words are not editable or selectable. How do I do this?
I have tried setting the target and action of the table view in IB, but it only calls the action method when the user clicks in the header of the table, not in one of the words.
I have tried setting the target and action of the NSTextField that the table cell view keeps in IB. This results in this error message being repeated in the console:
2018-01-02 14:14:32.080347-0800 WordExplorer[7089:21457459] Could not connect action, target class NSObject does not respond to -relatedWordClick:
However the target class does respond to the selector. (I connected it in IB directly, so clearly, it does!) It is also not a simple NSObject, so I'm guessing that something else is going wrong there.
I have tried manually calling -setTarget: and -setAction: on the NSTextField contained in the table cell view in my delegate's -tableView:viewForTableColumn:row: method. This has no effect, and the debugger shows that despite calling those methods, they do not set the text field's action or target method. (Though, given this is Xcode we're talking about, it's likely that's just a debugger display issue.) I get no errors in the console like when I make the connection in IB, but it also does not call the appropriate method.
Do I need to make custom view class and use that for the table cell view? Or is there a simpler way to get clicks (and preferably double-clicks) on words in my list?
Simply create an IBAction on the object you have as the NSTableView's target, and then set the NSTableView's doubleAction property to the selector for that IBAction, and you can handle double-click events easily.

NSResponder and multiple NSTableView - who sent message?

I've got two NSTableView in a single NSViewController, and each has their own NSArrayController to handle what exists. I'm now trying to wire up the Edit->Delete button. How do I know, when the delete method is called, 'who' sent that message?
Specifically I want to know whether I was clicked into the first table view or the second one when I then chose the Delete menu item. The 'sender' to the delete method is just the NSMenuItem so I can't back-track that to the table.
Get firstResponder of the window and follow nextResponder until you find a table view.

Enabled NSTableView refuses to resign first responder and eats all the events sent to first responder

I have an NSTableView and it eats all events sent to the first responder. Before adding table view, everything was perfect, and all the messages sent to the first responder were sent correctly to my NSDocument subclass.
As soos as I added table view, it insists on always having focus. The focus indicator around it never disappears unless an external sheet view controller (or something similar) gains focus. When table view has focus, my messages sent to the first responder doesn't work with keyboard shortcuts. They work when I click them from the menu bar by pointer though.
If I set "refuses first responder" it doesn't change anything. If I set "enabled" to false, then my app returns to normal behavior (though I obviously can't interact with the table view).
How can I prevent table view's "always focused" behavior. I've tried In a view-based NSTableView, how make a control the first responder with a single click?'s answer but didn't change anything.
Since I've subclassed NSTableView, I've overridden becomeFirstResponder and returned NO without doing anything, and it worked great! I can interact with the table view freely, it just doesn't gain focus.

Understanding first responder behavior

From the app delegate, I make a window and set it's contentView to be a view programmatically generated from a plist specification. I then bring the window to front. The window has a toolbar, and when the buttons on the toolbar are pressed, it is supposed to display a different contentView.
I have found that the first content view appears with its topmost text field subview already selected as first responder, but changing the view from the toolbar (it sets contentView on the window) to a different view will not select any of that view's text fields as first responder.
I want to have consistency, so ideally either it would never auto-select a control as first responder or it would always auto-select a control as first responder, but I don't really understand what process is making the control first responder in the first place.
Could somebody please explain what is causing that, so I can either prevent it or try to emulate it when switching views?
hussain Shabbir's answer is on the right track, but misses a few things.
First, setting the window's initial first responder, and then making the same view its first responder, is redundant. The point of the first is to cause the second.
Second, you need to set the window's initial first responder before making the window visible:
Sets a given view as the one that’s made first responder (also called the key view) the first time the window is placed onscreen.
If the window is already visible when you set its initial first responder, nothing will happen.
You need to set the initial first responder before you make the window visible for the first time.
The best place to do that is not in code at all—it's in the nib.
You would then not have either of those lines of code.
Better yet:
The window has a toolbar, and when the buttons on the toolbar are pressed, it is supposed to display a different contentView.
Have you considered using NSTabView? It handles this automatically (every tab view item has its own initial first responder outlet).
If you want when you click on different views your textfield should be become first responder, Then the two lines of code below should work:-
Here on the basis of your condition use these below lines:-
[[self window] setInitialFirstResponder:(NSView *)YourTextFieldName];
[[self window] makeFirstResponder:(NSView *)YourTextFieldName];

Clean way to resign first responder of NSSearchField when done?

In my application I have an NSSearchField that is bound to an arraycontroller which performs searches as the user types.
The problem is that the search field never resigns firstresponder-status once it receives it.
What would be the cleanest way of resigning firstresponder status when the user presses Enter or clicks outside of the search field? If possible I would prefer to do as much work as possible in Interface Builder.
[searchField.window makeFirstResponder:nil]
If you just want to get rid of the focus ring, you can disable it in the NIB.
If you want to resign first responder when the user clicks empty space in the window, you have to use a custom NSView as the window's content view and override mouseDown: to call the above method.

Resources