Cocoa: NextKeyView - Tab Order - cocoa

in my cocoa application I want to change the tab order of the controls so I can switch from a textfield to a button. I did connect the nextKeyView property of the textfield with the button but it seems to have no effect at all.
I already activated the appropriate system settings for Keyboard so I can tab to all controls now. It works fine but not in the order I set as nextKeyView.

You need to connect your window's initialFirstResponder outlet to at least 1 field. Some controls like NSTabView have one more initialResponder. So if you have anything inside tabview you need to connect them also.
Overall logic is you need to connect all initialresponde to atleast 1 field

The answer provided by #sach solved this for me.
I created a new storyboard project, and added 3 text fields. I set a custom order by linking them together with nextKeyView in Interface Builder, but this had no effect at runtime. This is the simplest test case that I could come up with to replicate your (and my) problem.
To solve it using #sach's answer, create a new outlet and connect it to one of the NSTextFields:
#IBOutlet var firstTextField: NSTextField!
In the ViewController, I then added:
override func viewWillAppear() {
// Must execute this after the window is connected
self.view.window!.initialFirstResponder = nameField
}
Re-run and the text fields cycle properly according to the order set using the nextKeyView links

Related

UIViewController as a popup in Xamarin iOS

In the current project,I am using an UIViewController with 2 text Fields and a text area.
Text fields are used as drop-down (custom logic) and based on drop-down selection information is displayed in text area for e.g. State and city are two drop down. On click of State drop down city data is populated in second drop down and on selection of city corresponding info is fetch and displayed in Text-area.
I have a requirement to move this logic to custom popup. Can anyone guide me how to achieve this with minimal changes in Xamarin iOS.
It would use UIPopoverController in this care. You already have a view controller with all the UI elements. You can use it as the DetailViewController so you don't have to change that much. Only it's size and the background. You can use it for both iPhones and iPads.
Here you have a sample project with source code:
https://developer.xamarin.com/samples/monotouch/Popovers/
Create a new UIViewcontroller in the storyboard, set the background colour of the main view to transparent, then create another view on top of that and put in any controls you want to display etc. then in the UIViewcontrollers init method add in the following:
public OverlayView(IntPtr handle) : base (handle)
{
ModalPresentationStyle = UIModalPresentationStyle.OverCurrentContext;
}
That way the background view that you've set as transparent won't just show black, it'll show in the context of the screen that called it, then you just present it as you would any other view, and add in some dismiss action events if you want it to pass data back etc. Hope this helps.

Continuous NSTextField

I have a NSTextField and Label whose value is bind to same NSString in the view Controller
The problem here is the label only gets updated when I press Tab.
How do I make it continuous, so that what ever I type in the text box gets reflected in the label immediately?
As of now I am using -(void)controlTextDidChange:(NSNotification *)obj; selector, but I am expecting a binding only solution.
Select the relevant NSTextField in Interface Builder, then navigate to the Bindings Inspector. You need to make sure Continuously Updates Value is checked:

How does one display a new view controller in the same Mac window?

I'm fairly new to Mac development and am slightly confused by the new "storyboard" feature in Xcode 6. What I'm trying to do is segue from one view controller to another in the same window. As of right now, all the different NSViewControllerSegues present the view controller in a new window, be it a modal or just another window. What I'd like to do is just segue within the same window, much in the same way one would on iOS (though an animated transition is not crucial). How would this be achieved?
If you provide a custom segue (subclass of NSStoryboardSegue) you can get the result you are after. There are a few gotchas with this approach though:
the custom segue will use presentViewController:animator so you will need to provide an animator object
because the presented view is not backed by a separate Window object, you may need to provide it with a custom NSView just to catch out mouse events that you don't want to propagate to the underlying NSViewController's view
there's also a Swift-only glitch regarding the custom segue's identifier property you need to watch out for.
As there doesn't seem to be much documentation about this I have made a small demo project with custom segue examples in Swift and Objective-C.
I also have provided some more detail in answer to this question.
(Reviving this as it comes up as first relevant result on Google and I had the same problem but decided against a custom segue)
While custom segues work (at least, the code given in foundry's answer worked under Swift 3; it needs updating for Swift 4), the sheer amount of work involved in writing a custom animator suggests to me that their main use case is custom animations.
The simple solution to changing the content of a window is to create an NSWindowController for your window, and to set its contentViewController to the desired viewController. This is particularly useful if you are following the typical pattern of storyboards and instantiate a new ViewController instance every time you switch.
However.
The NSStoryboard documentation says, quite clearly in macOS, containment (rather than transition) is the more common notion for storyboards which led me to look again at the available tools.
You could use a container view for this task, which adds a NWViewController layer instead of the NSWindowController outlined above. The solution I've gone with is to use an NSTabViewController. In the attributes inspector, set the style to 'unspecified', then select the TabView and set its style to 'tabless'.
To change tabs programatically, you set the selectedTabViewItemIndexof your TabViewController.
This solution reuses the same instance of the ViewControllers for the tab content, so that any data entered in text fields is preserved when the user switches to the other 'tab'.
Simple way with no segues involved to replace the current view controller in the same window:
if let myViewController = self.storyboard?.instantiateController(withIdentifier: "MyViewController") as? MyViewController {
self.view.window?.contentViewController = myViewController
}

Specify editing NSTextField inside NSPopover on appearance

I'm working on an app that presents an NSPopover containing a number of NSTextFields. While I can tab between these fields as I expect, the popover is selecting a particular text field to be in the editing state when it appears, and it's not the field I want to edit; I'd like to be able to define which text field is editing on popover appearance programmatically (or in Interface Builder). How can I do this?
I've set up the appropriate key view loop by connecting IB outlets for all the various text fields involved, and I've hooked up the popover's nextResponder property to the text field I want to edit first, but that doesn't seem to have an effect - the popover will still select its preferred text field instead of mine. The Window Programming Guide suggests that I set the initialFirstResponder outlet of the window to the view I want selected, but an NSPopover is not an NSWindow and has no initialFirstResponder property (unless I'm missing something obvious).
Is there any way to specify which NSTextField I want to be editing when an NSPopover appears?
I think you said you tried using -makeFirstResponder: and passing the text field. This will set the window's firstResponder, but that's not the same as initialFirstResponder and the window must have initialFirstResponder set to something other than nil in order to respect the key view loop. (Source) A slight tweak to what you tried worked for me:
- (void)popoverWillShow:(NSNotification *)notification
{
// Set the window's initialFirstResponder so that the key view loop isn't auto-recalculated.
[[myField window] setInitialFirstResponder:myField];
}
I think you can make this work by setting all the text field's that you don't want to have focus to "selectable" instead of "Editable" in IB, this should leave the one text field you want to start with as the first responder. Then, in your popoverDidShow: method, set them all back to editable, and you should be able to tab between them as usual.

Cannot bind NSSlider in IB?

I just created a new Xcode project. In the AppControl class Header file I have the following objects defined (and some other ones, too):
IBOutlet NSImageView *inputImageView;
IBOutlet NSImageView *outputImageView;
IBOutlet NSTextField *myNoiseLevel;
IBOutlet CGFloat *mySharpness;
After putting the basic code into the .h and .m files, I then went into Interface Builder and created my UI. I was able to bind the two NSImageView controls in IB to the corresponding NSImageView objects listed above. And I was able to bind a couple of other objects/controls, also. But I am NOT able to bind the last two items listed (myNoiseLevel and mySharpness) to the NSSlider controls I have on the application main window. I'm not sure why. I know this kind of thing is probably hard to diagnose, because it is not "strictly code related," but if there is something "tricky" about binding sliders please let me know what the main "suspects" are that I should check.
This is my first attempt to use a slider control through IB. I have a book (Cocoa programming for Mac OS X, 3rd ed., by A. Hillegass) that I am using to learn about the basic way to do this stuff. And he has a slider example in there. But his slider example is "continuous" and it uses key path binding. I think this is overkill for what I want/need to do -- I just want to pull the value from the slider when another button is pushed (no need for "continuous" update). So I am trying to directly bind the "outlets" listed when I right-click on my App Control object (one for each of those items shown above), to the slider controls on my window. But when I cntl-drag from the AppControl outlet up to the corresponding slider, the slider will not "accept" the arrow I'm dragging.
Does this make sense? Any idea what I'm doing wrong and/or what I need to do to make the binding work? I have tried saving / building / closing & reopening IB and Xcode -- all to make sure IB has the latest version of everything. Still no luck, though.
One last thing ... What I really need are CGFloat numbers, from the slider. Can I simply declare the Outlet as CGFloat type ... or do I need to define it as NSTextField (or something else), and then convert it to Float in my program? You can see in the IBOutlets I pasted above, that I was trying different data types for the outlets (trying to see if my defining them as CGFloat was somehow preventing the bindings).
Make the outlet an NSSlider*. You should then be able to connect to it. When you need the value (eg, in response to the button press you mention) call [yourSliderOutletName doubleValue].
More generally: an IBOutlet is an ivar that can be filled in with a pointer to the actual object awoken from a NIB file. As such, it needs to be of an appropriate type to hold that pointer -- the object's actual class, or one of its superclasses or protocols, or (least informatively) id. You can't just arbitrarily connect an object to any old variable, like your CGFloat. There's no implicit conversion -- how is the system supposed to know what you want?

Resources