How to change value of the NSTextField instantly as we type? - objective-c

There are two outlets connected to my ViewController.swift file.
#IBOutlet var myOutlet: NSTextField!
#IBOutlet var yourOutlet: NSTextField!
There is an action connected too.
#IBAction func myAction(sender: NSTextField) {
self.yourOutlet.doubleValue = myOutlet.doubleValue - 10
When i run the app, it works.
I enter 15 to text field that myOutlet connected, then hit the enter. And field that yourOutlet connected, takes the value of 5.
If there is no enter button needed, it would be better. So how to make the value change instantly, as we type?
Thanks for the answers.

I did not get a chance to do swift and OSX development, but I can lead you to the solution.
Take a look at textDidChange(_:)
Posts a notification that the text has changed and forwards this
message to the receiver’s cell if it responds.
Declaration
func textDidChange(_ aNotification: NSNotification)
Parameters aNotification The NSControlTextDidChangeNotification
notification that is posted to the default notification center.
Discussion This method causes the receiver’s delegate to receive a
controlTextDidChange: message. See the NSControl class specification
for more information on the text delegate method.
So to achieve your goal, you would implement this delegate, it will get called each time you edit the text inside of the NSTextField.Then inside of that delegate block you will provide the logic needed.

Related

How to get characters from emoji picker [ctrl-command-space]

on OS X the 'Emoji & Symbols' picker can be started from the menu or [ctrl-command-space] how do I get the characters from this in my view? (just an NSView with text handling in core text).
i.e. I double click on the emoji in the picker and how do I receive it in my view - I'd guess there's a delegate I have to set somewhere - but can't seem to find the docs - I'm probably not calling it the right thing when I google
I've made a basic app
and added the lines below to the view controller
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.window?.makeFirstResponder(self.view)
self.view.becomeFirstResponder()
and made a view MyNSView with and set the view in the storyboard to MyNSView
override public func keyDown(with event: NSEvent) {
interpretKeyEvents([event])
}
When I use the emoji picker, the keydown doesn't fire (I put a breakpoint on it). Maybe the emoji comes from another method?
Seems I have to implement NSTextInputClient - see https://developer.apple.com/library/content/samplecode/TextInputView/Introduction/Intro.html
Seems I have to implement NSTextInputClient - see https://developer.apple.com/library/content/samplecode/TextInputView/Introduction/Intro.html

How to make NSTextfield lose focus when Enter is pressed?

I want to make a text field in which if I click out of it, or press enter, it makes it lose focus. As in the focus ring disappears. I've have seen situations like this, but I do not know where to place the code for it. Can anyone show me how to make the NSTextfield lose it's focus?
One method would be to implement the NSTextFieldDelegate, assign the delegate to your text field, and have it call a selector (a method in your code that changes makes the first responder = nil). The delegate will be called with a message when the text field is finished receiving input. Check out the API here for more information:
https://developer.apple.com/library/mac/documentation/cocoa/reference/NSTextFieldDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intf/NSTextFieldDelegate
For people out there as lazy as me, here is some code.
This is the cut down NSTextfieldDelegate method i used:
func control(_ control: NSControl, textShouldEndEditing fieldEditor: NSText) -> Bool {
DispatchQueue.main.async {
self.textField2.window?.makeFirstResponder(nil)
}
return true
}
https://developer.apple.com/documentation/appkit/nstextview/1807135-resignfirstresponder?language=objc
resignFirstResponder Docu says the following:
Use the NSWindow method makeFirstResponder:, not this method, to make
a text view the first responder. Never invoke this method directly.
// don't use this as the name may suggest (at least it did for me)
self.textField2.resignFirstResponder()

how to fire mapView:didSelectAnnotationView

I'm new to iPhone development. I've been reading several questions on how to make a google maps annotation callout window accept line breaks. Every tutorial I've read requires me to fire the mapView:didSelectAnnotationView method. But I have no idea how to trigger this. things I've tried include
putting the method in my MapViewController.m file which extends UIViewController
putting the method in a MapView.m file which extends MKMapView, then have my Mapview element in my storyboard reference it as the class to use
There's so much about xcode, objective c, and iphone development that I don't understand, so i can't tell where my problem lies.
At the moment, my map does plot my desired marker on the desired location. I just need to understand how to fire the mapView:didSelectAnnotationView and mapView:viewForAnnotation functions before I can start customizing the call out box.
Does anyone have step by step instructions on how to trigger these functions?
A bit of background
A few things to note:
You don't call mapView:didSelectAnnotationView. The MKMapView calls that function on it's delegate. In other words, when you set up an MKMapView, you tell it: "hey, listen, anytimme you need to tell me what's happening on the map, go tell this guy, he'll handle them for you". That "guy" is the delegate object, and it needs to implement mapView:didSelectAnnotationView (that's also why its name "did select", ie, it already happened, as opposed to "select"). For a simple case, the delegate is often the UIViewController that owns the MKMapView, which is what I'll describe below.
That method will then get triggered when the user taps on one of your annotations. So that's a great spot to start customizing what should happen when they tap on an annotation view (updating a selection, for instance).
It's not, however, what you want if you want to customize what annotation to show, which is what it sounds like you're actually after. For that, there's a different method just a few paragraphs earlier on the same man page: mapView:viewForAnnotation. So substitute this method if you find that mapView:didSelectAnnotationView isn't what you were looking for.
What you can do
If you got as far as a map with a marker, I'm guessing you have at least:
* a view controller (extendeding from UIViewController, and
* an MKMapView that you've added to the view for that view controller, say named mapView
The method you want to fire is defined as part of the MKMapViewDelegate protocol.
The easiest way to get this wired is to:
make your UIViewController the delegate for you MKMapView
in code, say in your viewDidLoad, of your MapViewController.m you could do mapview.delegate = self, OR
in Interface Builder, you could drag the connection from the the MKMapView delegate property to the file's owner
then, define a method on your UIViewController called mapView:didSelectAnnotationView, declaring it just like the protocol does, in your MapViewController.m file:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
// whatever you need to do to your annotation and/or map
}
Good luck!
mapView:didSelectAnnotationView is a delegate method of the map view, you can read about it here:
MKMapViewDelegate Protocol Reference
You don't need to call it, the map view will call it "by it self" and send it to every view/view controller that registered as it's delegate.
What do you need to do
Basically you need to add the MKMapViewDelegate on your .h file, what will look something like this:
#interface someViewController : UIViewController <MKMapViewDelegate>
Then in the .m file, after you instantiate the map view you should add:
mapView.delegate = self;//were self refers to your controller
From this point and on your controller will be able to "receive messages" from the map view which are the methods that you can see on the MKMapViewDelegate reference I linked to.
So to implement the mapView:didSelectAnnotationView you need to add in your .m file
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
//if you did all the steps this methosd will be called when a user taps the annotation on the map.
}
What is happening
What happens in the background is:
The map view has a method (Apple codded) that handles the AnnotationView touch events.
When a touch event take place it sends a "message" to all of it's delegates saying "Hey a user did Select Annotation View on this map, Do with it what ever you need".
usually it looks like that:
[self.delegate mapView:someMapView didSelectAnnotationView:someAnnotationView];
Then every view/controller that assigned itself as a delegate and implemented the method will cal this method.
Good luck
Place *place = [[Place alloc] init];
PlaceMark *placeMark = [[PlaceMark alloc] initWithPlace:place];
[self.mapView selectAnnotation:placeMark animated:YES];

NSCollectionViewItem double-click action?

How do I set an action for when a user double clicks an NSCollectionViewItem. NSTableView, for example, has the setDoubleAction method. Is there something similar for NSCollectionView?
Thanks
I know this question is ancient, but it comes up as the third result on Google right now, and I've found a different and very straightforward method that I haven't seen documented elsewhere. (I don't just need to manipulate the represented item, but have more complex work to do in my app.)
NSCollectionView inherits from NSView, so you can simply create a custom subclass and override mouseDown. This is not completely without pitfalls - you need to check the click count, and convert the point from the main window to your collection view's coordinate, before using NSCollectionView's indexPathForItem method:
override func mouseDown(with theEvent: NSEvent) {
if theEvent.clickCount == 2 {
let locationInWindow = theEvent.locationInWindow
let locationInView = convert(locationInWindow, from: NSApplication.shared.mainWindow?.contentView)
if let doubleClickedItem = indexPathForItem(at: locationInView){
// handle double click - I've created a DoubleClickDelegate
// (my collectionView's delegate, but you could use notifications as well)
...
This feels as if I've finally found the method Apple intended to be used - otherwise, there's no reason for indexPathForItem(at:) to exist.
You'd probably want to handle this in your NSCollectionViewItem, rather than the NSCollectionView itself (to work off your NSTableView analogy).

Can you set a navbar's edit button in Interface Builder?

It's easy enough to set up a table view to allow editing. Just add one line to your UITableViewController:
self.navigationItem.rightBarButtonItem = self.editButtonItem;
This line adds an edit button on the nav bar that will change the table to editing mode and change its button text to "Done" while editing.
Is it possible to set this up in Interface Builder? I see that you can add a UIBarButtonItem and can set its "Identifier" to "Edit", but I don't see the expected behavior.
BTW, what does the "Identifier" in the Attributes panel do?
Yes, you can add UIBarButtonItems in Interface Builder, and they should work.
The identifier lets you use a preset button (like Edit or Reload), or you can choose Custom and make your own button.
EDIT: I may be able to help further if you could explain how UIBarButtonItems added through IB don't work.
UPDATE: UIViewController.editButtonItem is a special method that returns a UIBarButtonItem that invokes the view's setEditing method. You can achieve the same effect by creating a method that does the same thing and connecting the selector to your UIBarButtonItem in IB.
In your header file:
- IBAction edit:(id)sender;
and in your implementation file:
- (IBAction) edit:(id)sender {
[self setEditing:YES animated:YES];
}
then connect the selector to the UIBarButtonItem.
However, you might not be able to create this connection in the default Navigation-Based Application template since the Table View is in a separate file.
Have a look here: http://blog.tmro.net/2009/05/uitabbarbuttonitem-did-not-change-its.html
If you want your button to be able to change its label dynamically make sure you use a custom identifier otherwise its title will be immutable.
We still can't seem to do this specifically in Interface Builder as of Xcode 9.4.1. It's very easy to do in code, though.
You don't need to set up the button in IB at all. Simply add this code in your viewDidLoad method:
navigationItem.leftBarButtonItem = editButtonItem
That automatically sets up the Edit button, which turns to Done so the user can end editing.
To do anything custom associated with the editing process, override the view controller's setEditing(_ editing: Bool, animated: Bool) method.
For example, if you have a table view whose editing needs to be turned on and off, you can do this:
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
tableView.setEditing(editing, animated: animated)
}
Make sure to call super.setEditing here.
Note: if you're using a UITableViewController, setEditing is already set up in the super class to handle the table view. You don't need to override it, unless you have other custom code you want to include when editing is enabled/disabled.