Initialize selected radio button (NSButton) group in AppKit - objective-c

I have dozens of radio button groups, each with their outlets connected to their group IBAction. They all function exactly as one would expect.
QUESTION:
But in my initialization (in the NSViewController) for the view, I go through each radio button outlet (in each group) and set its state (NSControlValueON/OFF), based on which button is actually the "ON" button. Should that even be necessary? Does setting the state of any in the group automatically toggle the others off, then call the IBAction? Or is there a way to simulate a click on the desired radio button?
A useful method would be to provide ANY NSControl* in the group, with a desired tag, and have that radio button turned on, and the others turned off.
NOTE: my code is Objective-C, but I'll abstract a Swift answer, too!

Related

is single radio button available in cocoa?

I am trying to drag-drop a single radio button from object library in cocoa. But there is "radio group" object is available to drag-drop. In radio group has two radio button.
Is there any way to create a single radio button in cocoa application or hide the one radio button from radio group?
Thanks
You can make it one by going to attribute inspector and set the cell count to 1. but you have to handle the behaviour by your self logically.
Single radio button is not available in object library in cocoa. You can just use a normal UIButton and give its normal and selected images in Interface Builder.
Alternatively, you can just use a custom library for radio button like this one : https://github.com/onegray/RadioButton-ios
You should use a simple UIButton.
You can set different texts/images depending on a button status, like Devanshi suggested. The if/else approach is a bad idea though, because cocoa already provides these and are much more simple and small.
There are two ways, either storyboard (if you use it) or programatically, wherever you create your button (most likely viewDidLoad).
If you are using Storyboard
Storyboard is pretty straightforward, select your button, and under the "State" you can chose different settings. Each settings will actually load different parameters for the next settings. Like the title and image for example.
Just go on state "default" and set an unchecked box as image.
(You can)go on state "Highlighted" and set a temporary highlighted box as image; this is not mandatory.
Then go on state "Selected" and set a checked box as image.
And you're done.
If you are using only code
The programatic way to do this is fairly simple.
I assume we have a button called btSend,
UIControlStateNormal, UIControlStateSelected, UIControlStateDisabled, UIControlStateHighligted, are the states you can use. I used disabled and normal (enabled) here.
[self.btSend setImage:[UIImage imageNamed:#"SendIcon.png"] forState:UIControlStateNormal];
[self.btSend setImage:[UIImage imageNamed:#"SendIconGrayed.png"] forState:UIControlStateDisabled];
With this, you'll be up and running too.
After setting that up
Now that your buttons know what to show depending on their state, you need to add a selector method for your action (an IBAction), in which you will need to invert the state of your current button. You probably already have that, just add a boolean.
checkBoxSelected is a boolean that I created as an instance variable (on top of .m file). You can set it to "NO" in viewDidLoad if your radio is not selected by default, and to YES if it is selected by default.
#implementation TermViewController{
BOOL checkBoxSelected;
}
here is the method that is called when I press the button
- (IBAction)tapRadioButton:(id)sender {
checkBoxSelected = !checkBoxSelected;
[_btCheckbox setSelected:checkBoxSelected];
}
You probably have "something" that checks if your checkbox is selected, to know that, you can either get the state of your button by using self.yourButton.state. This will return a UIControlState, just check if it's Normal or Selected or Disabled or HIghlighted.
Or you can check the Boolean "checkboxselected" if it's YES or NO :)
If you have many radio buttons, you can save all those boolean values in a dictionary. the key would be your button number for example, and the object would be YES or NO. if you press the button, (like shown before), change the button state and also change it in the dictionary. At the end you have all your states in the dictionary.
I didn't explain all that in my first writing because that wasn't really a part of your question :) I hope this helps.
For radio button can use simple UIButton and maintain state of it and replace the image of on click event.
1) Declare globally in view
BOOL isChecked;
2) On button click event
if (isChecked)
{
[_btnRadioBox setImage:[UIImage imageNamed:#"chk_uncheck.png"] forState:UIControlStateNormal];
}
else
{
[_btnRadioBox setImage:[UIImage imageNamed:#"chk_check.png"] forState:UIControlStateNormal];
}
isChecked=!isChecked;
3) And get the status of it.
if (isChecked)
{
// Here write code of radio button when selected
}
else
{
// Here write code of radio button when unselected
}
You can use MVRadioButton to add animated radio button in iOS. This is very simple Drop in and easy to integrate Custom Control.
Its using CoreAnimation and Layers to Give it look and feel exactly like a Traditional Radio button that we have seen on Web.

Buttons as Outlets vs IBActions [Objective C + Xcode]

What is the point of ever setting a button as an outlet? I am following a tutorial and the teacher didn't really mention why he set a button as an outlet. A button is suppose to do an action/call a method and so we set it as an IBAction.
He sets the button as an outlet and then proceeds to change the text of the button through Xcode in viewDidLoad, but why not just keep it as an IBAction and change the text by using setTitle: forState:UIControlStateNormal ?
Isn't a button suppose to cause an action by definition?
in some logic cases you would need to change the behaviour of the button , e.g. upon invoking an action (triggered by other event )you will need to disable it or change its backgroundColor or text.
you don't have to set at all times , but in many cases it is really useful

NSOutlineView select with the first click

I have an NSPanel with a NSOutlineView to display my data. I want to select a row with a first click inside the NSOutlineView even if the panel is not in focus (i.e. not the key window) I have a delegate that allows selection and I have overridden the NSOutlineView class to override the acceptsFirstMouse: method, but I could not get the first click selection.
I checked the mouseDown event and it fired without any problems (in my class that overrides) when the panel was and wasn't the key window. But when the panel is not key, NSOutlineViewDelegate method shouldSelectItem: is not called.
What am I missing/doing wrong?
You just need to subclass your NSTableOutlineView and override:
- (BOOL)needsPanelToBecomeKey
to return NO.
NSView class reference states:
Overridden by subclasses to determine if the receiver requires its
panel, which might otherwise avoid becoming key, to become the key
window so that it can handle keyboard input and navigation.
Discussion
Such a subclass should also override acceptsFirstResponder
to return YES.
This method is also used in keyboard navigation. It determines if a
mouse click should give focus to a view (make it first responder).
Some views will want to get keyboard focus when you click in them, for
example text fields. Other views should only get focus if you tab to
them, for example, buttons. You wouldn't want focus to shift from a
textfield that has editing in progress simply because you clicked on a
check box.
Source: Apple documentation

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".

Growl notification like nswindow level

I am writing a notification system just like growl. The notification is a window and it's level is set to NSModalPanelWindowLevel. The only problem is, I have a button in that window and when the user wants to click that button, he/she has to click it twice. But, for example, in growl, no matter what window you have opened, you just simply click the notification and it registers a click.
So is it a level problem? If so, what should I set it to? Thanks
In your custom controls that make up the view content of the window, you will likely want to override NSView's -acceptsFirstMouse: method to return YES:
Discussion
The receiver can either
return a value unconditionally or use
the location of theEvent to determine
whether or not it wants the event. The
default implementation ignores
theEvent and returns NO.
Override this method in a subclass to
allow instances to respond to
click-through. This allows the user to
click on a view in an inactive window,
activating the view with one click,
instead of clicking first to make the
window active and then clicking the
view. Most view objects refuse a
click-through attempt, so the event
simply activates the window. Many
control objects, however, such as
instances of NSButton and NSSlider, do
accept them, so the user can
immediately manipulate the control
without having to release the mouse
button.
Not sure if this is what Growl does, but you might be able to listen for mouse over events in the window and use them to activate/deactivate the window prior to the click. I suspect your issue is that the first click is being eaten by the activation of the window.
Just a guess on that though.
To learn how to handle mouse over events, check out this documentation:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/EventOverview/TrackingAreaObjects/TrackingAreaObjects.html