How can I get the value of an NSSlider continuously? - objective-c

It seems like NSSlider in Cocoa does not provide a delegate to receive an event like Value Changed for a UISlider.
How can I get the value of an NSSlider continuously and display it in an NSTextField, for example?

You need to research Cocoa's Target/Action mechanism. This is a basic Cocoa concept you'll need to understand. The slider (and any other control) can be given a target (some controller object) and an action (the method to call against that controller object).
The action is fired when the user stops dragging by default. Check the slider's Continuous property in Interface Builder to cause it to trigger the action as you're sliding it.

One advantage of using the timer approach is that it works for the case of using the keyboard rather than the mouse to adjust the slider. If the user has "Full Keyboard Access" turned on in System Preferences, they can use the Tab key to give the slider focus. They can then hold down an arrow key so that autorepeat kicks in, whereupon you have a similar situation to dragging with the mouse: the target/action is firing repeatedly, and you want to wait for a moment of calm before saving to the database.
You do need to be careful not to delete your NSTimer prematurely. For example, if the user quits the app during those couple of seconds you probably want to "flush" the slider value to the database before terminating the process.

Programmatical solution based on the answer of Joshua Nozzi:
Swift
slider.isContinuous = true
Objective-C
slider.continuous = YES;

Related

Is there a way to disable sounds (such as "beeps") in my mac app?

I know I need to dig the reason why my app is beeping in the code, etc.
But I was wondering, is there a global setting to disable sounds all over my app screens?
this is very little information to go on, but usually your application is beeping when the responder chain comes up with no object that can respond to an event on the screen or keyboard.
For instance, if you type text in an active view and the view doesn't allow for text editing, the view sends the key down event to its super view. For a view this can end by the NSPanel or NSWindow or BSWindow controller. The last responder in the chain invokes the noResponderFor: method, which, when not implemented, will give a beep. If you don't want it to beep, override this method to do something else.
Based on your information I can't give you any other information.

NSTableView early detection of edit session

I've a NSTableView (view-based) whose delegate (my windowcontroller, in this case) needs to be notified as early as possibile of Text editing session starts.
I've tried with the Text Delegate method
- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor;
but this not working in my case.
The event gets triggered (and the delegate invoked) if and only if i hit some key in the keyboard.
If, by any chance, i click outside the control without having typed anything, the edit session silently stops without notifying anybody.
Any help is appreciated.
#theAmateurProgrammer
Thank you for your suggestion. Well, what you suggest would do only in case of mouse events. Instead, i need to detect the start edit session event always, also in case of, for example, programmatically triggered editing.
However i've found the solution. I subclass the table view and then i override the validateProposedFirstResponder method.
The responder, actually, is the TextField which is about to start editing.

How to force an NSWindow to be always active/focused?

I have a transparent NSWindow that follows the user's screen everywhere he goes (the NSWindowstays in front of every app, no matter what, even fullscreen apps).
In that NSWindow i have a mouseDown event that shows a popup. Let's say i'm on safari in fullscreen mode and i have my Window in front of it, i click on safari and i click again on my Window: nothing happens, the mouseDown doesn't occur. I have to click again so the mouseDown event is triggered.
How can i force my NSWindow to be always active so i don't have to click it 2x to trigger the mouseDown when i click on a background app and click in my window again?
Thank you!
I'm not sure if this is exactly what you want (it's not quite a window wide setting), but, from the documentation:
By default, a mouse-down event in a window that isn’t the key window
simply brings the window forward and makes it key; the event isn’t
sent to the NSView object over which the mouse click occurs. The
NSView can claim an initial mouse-down event, however, by overriding
acceptsFirstMouse: to return YES.
The argument of this method is the
mouse-down event that occurred in the non-key window, which the view
object can examine to determine whether it wants to receive the mouse
event and potentially become first responder. You want the default
behavior of this method in, for example, a control that affects the
selected object in a window.
However, in certain cases it’s
appropriate to override this behavior, such as for controls that
should receive mouseDown: messages even when the window is inactive.
Examples of controls that support this click-through behavior are the
title-bar buttons of a window.
Or you could try fiddling with
- (void)sendEvent:(NSEvent *)theEvent
and see if you can handle events in a custom way.
If you add a borderless NSButton instance to your window's view and set your image as the button's image (and as its alternate image, to make it more beautiful), it will work out of the box: Just connect the button's action method to your app delegate (or the object where you want to process the click action). A click on the image (i.e. the button) will then trigger the button's action method, no matter which window is active.
This worked for me, hope that will be helpful, This will keep your window always on Top of all applications
[self.window makeKeyAndOrderFront:nil];
[self.window setLevel:NSStatusWindowLevel];
I think what you really should do is use an NSPanel (a floating palette -- a special kind of NSWindow) that will do exactly what you want in a way that's consistent with the OS rather than trying to fight intended behavior.
Here's the NSPanel documentation:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nspanel_Class/Reference/Reference.html
And here's some helpful and pithy information:
http://cocoadev.com/wiki/NSPanel
By default, an NSPanel will disappear when the application is inactive, but you can turn this off.
I apologize for not laying it out more fully ... pressed for time.
Edit:
Note that you can probably get your window to behave as desired simply:
"The NSView can claim an initial mouse-down event, however, by overriding acceptsFirstMouse: to return YES."
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/HandlingMouseEvents.html
You'll need to do this with any NSView subclass to skip the "activation click".

How to check if a NSWindow is visible

Is there a way to check if a NSWindow is visible or not? I want to display a sheet controller once the first window of my app became visible (the animation on 10.7 ended and the user can see the window!). If I just show the sheet in windowDidLoad, it results in a stupid looking animation (sheet rolling out, window popping out from the back). I know that NSWindowDelegate provides two methods which are invoked when a window either became the key window or the main window, however, this doesn't have to mean that the window is already fully visible at the time. This is even more noticeable on Lion where windows tend to pop up with this stupid animation.
I would go for something like this:
if ([myWindow isVisible]) {
// Do stuff
}
Or an an observer for this key path to be notified when the change occurs.
For what it's worth, you can also bind to the window.visible property. Xcode 4 may squawk at you, saying it's not a bindable property, but it will work.
This can be useful if you are trying enable/disable show/hide NSStatusItem based on whether the window is visible, as well as other approaches.
i.e. in Interface Builder:
Bind to: App Delegate
Model Key Path: self.window.visible

Handling mouse events on NSButton created in Interface Builder

I had a class project consisting in programming a swype-like. I had to do it in java, and you can have a look at it (with the code) here. For this summer, I'd like to port it in ObjC/Cocoa, and then improve it. I intend to use NSButtons for the keyboard keys, like the "Gradient Button" proposed by Interface Builder.
So, I looked about how to handle mouse events (I need mouse pressed, entered, exited, and released). For some objects, it looks like you have to use a delegate, but for NSButton, looks like the methods like -mouseDown and related are in the object itself.
My question is, how do I override the methods in interface builder objects ? I tried creating a subclass of NSButton, and setting my button's class to this subclass, but without results. Maybe trying to override the methods is not the right way to do it at all, I'm open to every suggestion, even if it is not event-handling related. And if it is relevant, I'm running OS X 10.6, with XCode 4.
Thanks for your time !
A lot will depend on why you need all of the various events. NSButton is a control, and as such works differently than a standard NSView.
If you mostly need to figure out when the button is pressed, you can do this by assigning an action in IB. This is done by creating a void method in your controller class of the form:
- (IBAction) myMouseAction:(id)sender
and then having it do what you need based on receiving the click. Then in IB, you can hook up this action to the button by control-clicking on the button and dragging to your controller class (likely the owner) and selecting your new method when prompted.
If you need fine-grained control, you should consider creating your own NSView subclass and handling the mouse actions yourself, as trying to override controls is a pretty complicated matter. OS X controls were architected for extreme performance, but they're a bit anachronistic now and generally not worth the work to create your own.
One other thing is that the mouseEntered:, mouseMoved: and mouseExited: events are for handling mouse movement with the mouse button up.
You are going to want to pay attention to: mouseDown:, mouseUp: and mouseDragged: in order to handle events while the mouse button is being held down.