How to control UIButton on View without IB - objective-c

I put some UIButtons on UIScrollView without IB.
If I click one button, other buttons are turned off except selected button.
But, When I click another button, other button ( except selected button) are turned off.
I can't confirm count of UIButtons on UIScrollView.
Because count of UIButtons are changed dynamically.
Without IB, How can I control UIButton on UIScrollView?
Plese tell me your advice. Thanks!

you can use:
NSUInteger count = 0;
for(id button in [scrollView subViews])
{
if([button isKindOfClass[UIButton class]])
{
count++;
}
}
NSLog("total buttons: %d",count);

You can tag the UIButtons when creating them [myButton setTag:MY_BUTTON_1] and later use this information when the button is tapped
-(IBAction)buttonPressed:(id)sender{
UIButton *button = (UIButton *)sender;
if ([button tag] == MY_BUTTON_1) { /* do something with this button */ }
else if ([button tag] == MY_BUTTON_2) { /* do something differently */ }
else return;
}

Related

How do I get a button to become disabled only when a table view has 0 rows?

I have two buttons - 'Insert row' and 'Delete row', created through interface builder.
When there are 0 rows in my table, I want the 'delete row' button to be greyed out.
I'm told that the way to disable a button is - [button setEnabled:no] or by unticking the 'Enabled' box in interface builder. However, either of these cases will not work for me.
Any suggestions?
Create an IBOutlet for your button in your .h file as
AppDelegate.h
{
IBOutlet NSButton* yourButton;
}
Then ctrl+drag from your button in xib to FileOwner/AppDelegate and connect the referencing outlet of button to yourButton in AppDelegate class.
Now, if your are populating the table view using data source methods, implement
AppDelegate.m
- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView;
{
if(![yourArray count])
{
[yourButton setEnabled:NO];
}
else
{
[yourButton setEnabled:YES];
}
return [yourArray count];
}
Are you sure that [button setEnabled:NO] doesn't disable the button? You need to set a different visual style for its disabled state to have it look disabled. Try testing if the button is enabled by tapping on it.
If you have done the bindings of your button then follow the below bindings.
For that you need to bind the button to Enable property - > Array Controller -> Selection - >
Model Keypath -> "#count"
Probably you have bindings to an array controller. Then you can bind the enabled property of the delete button to the canRemove property of the array controller.
if you are populating your table view through binding, here is the snippet you can try
if(![[arrayController arrangedObjects] count])
{
[button setEnabled:YES];
}
else
{
[button setEnabled:NO];
}
where arraycontroller is outlet of NSArrayconrtoller which content array in XIB.
You Should set UIButtonType and UIButton setTitle for default greyed out. For example programme should be like
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"delete row" forState:UIControlStateNormal];
button.enabled = NO;
button.frame = CGRectMake(20, 20, 100, 100);
And If you set background image for UIButton. You need to set your custom UIImage for enable and disable.
[button setBackgroundImage:[UIImage imageNamed:#"enable.png"]
forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"disable.png"]
forState:UIControlStateDisabled];

IBOutletCollection of UIButtons - changing selected state of buttons

I'm having an issue with multiple UIButtons in a view. I'd like the buttons to be selected individually, with multiple selected at a time (example: 10 buttons, with buttons 1, 4, 5, 9 selected).
In my header I have a property for the IBOutletCollection:
#property (retain, nonatomic) IBOutletCollection(UIButton) NSMutableArray *buttonToStaySelected;
In my implementation, I have an IBAction:
-(IBAction)selectedButton:(id)sender{
for (UIButton *b in self.buttonToStaySelected) {
if (b.isSelected == 0){
[b setSelected:YES];
} else
[b setSelected:NO];
}
}
The issue I'm having is when I select any of the buttons tied to the collection, they all change to selected. I know the problem most likely (almost certain) lies in the loop, but every condition I've tried to stipulate breaks the code and leaves none of the buttons able to "change" state.
UPDATED
To have them selectable, change state and check off multiple, I used this as my final code:
-(IBAction)selectedButton:(id)sender {
for (UIButton *b in self.buttonToStaySelected) {
if (sender == b) {
[b setSelected:!b.isSelected];
}
}
}
Thanks for all the help!
The selectButton: message is sent with an argument which specifies the button that was tapped, but you apply the action to all buttons in the collection, not just the button that was tapped.
-(IBAction)selectedButton:(id)sender
{
for (UIButton *b in self.buttonToStaySelected)
{
if (sender == b)
{
b.isSelected == !b.isSelected
}
}
}

how to set background image dynamically for dynamically created button using tag?

I have created a row of numberButtons inside a view dynamically.I am getting button highlighted when clicking any number.If I am clicking more than 1 in that row ,all of the clicked buttons get highlighted.What to do for avoiding multiple highlation?
I have used the code as follows
-(void)pressed:(id)sender{
UIButton *button = (UIButton *)sender;
if(!button.selected){
[NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:#selector(highlightButton:) userInfo:button repeats:NO];
} else {
[NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:#selector(unhighlightButton:) userInfo:button repeats:NO];
}
-(void)highlightButton:(id)sender{
UIButton *button = (UIButton *)[sender userInfo];
button.highlighted = YES;
button.selected = YES;
}
-(void)unhighlightButton:(id)sender{
UIButton *button = (UIButton *)[sender userInfo];
button.highlighted = NO;
button.selected = NO;
}
I'm assuming that you mean that every button you tap is highlighted without removing the previous highlight.
To only have one button highlighted at a time. Keep track of what button was highlighted and remove its highlight when tapping another button.
- (void)buttonTapped:(UIButton *)button {
if (button != [self lastSelectedButton]) { // don't re-highlight the same button
// remove the highlight of "lastSelectedButton"
[self setLastSelectedButton:button];
// add the highlight to "lastSelectedButton" (not updated to the new button)
}
// Do the rest of you button logic here ...
}
Override your select method by calling deselect method in the end.
So, when you click your control will be selected and deselected instantly.

Popup menu implementation from NSButton

How should I go about it?
I was thinking about...
[NSMenu popUpContextMenu:menu withEvent:event forView:(NSButton *)sender];
Yup.
On button action call
[NSMenu popUpContextMenu:menu withEvent:event forView:(NSButton *)sender];
where
menu : menu you want to show
sender : button you clicked
event : a new NSEvent you create
When you create the new NSEvent, specify the location as to where you want the popup menu to be shown.
Swift version of accepted answer
#IBAction func actionOccurred(sender: NSButton) {
if let event = NSApplication.sharedApplication().currentEvent {
NSMenu.popUpContextMenu(sender.menu!, withEvent: event, forView: sender)
}
}
Updated answer
Add NSMenu to the NSViewController in the storyboard as seen in the image
Connect the Outlet
Right-click on the button in the storyboard and connect the menu outlet to the menu that we have just added to the storyboard(Where arrow points in the image)
Add IBAction
#IBAction func menuClicked(_ sender: NSButton) {
var location = NSEvent.mouseLocation
location.x -= 10; location.y -= 10 // Menu appears below the button
let menu = sender.menu!
menu.popUp(positioning: menu.item(at: 0), at: location, in: nil)
}
As I have commented I find the ButtonMadness example less than perfect.
My implementation seems to work better. The menu is shown on mouse down, the button remains depressed throughout, the menu position can be specified and the menu is dismissed without subsequent spurious display.
To be honest NSPopupButton is a better choice in the majority of situations. I use this code mainly because of the convenience of having one class for buttons and popups and because the menu does not contain the popup control image and title. I load the menu from a separate nib and reuse it as is elsewhere in the app as required.
Note that it is trivial to add additional support for say a popover as well as menu.
NSButton subclass:
- (void)mouseDown:(NSEvent *)theEvent {
// if a menu is defined let the cell handle its display
if (self.menu) {
if ([theEvent type] == NSLeftMouseDown) {
[[self cell] setMenu:[self menu]];
} else {
[[self cell] setMenu:nil];
}
}
[super mouseDown:theEvent];
}
NSButtonCell subclass:
- (BOOL)trackMouse:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp
{
// if menu defined show on left mouse
if ([event type] == NSLeftMouseDown && [self menu]) {
NSPoint result = [controlView convertPoint:NSMakePoint(NSMidX(cellFrame), NSMidY(cellFrame)) toView:nil];
NSEvent *newEvent = [NSEvent mouseEventWithType: [event type]
location: result
modifierFlags: [event modifierFlags]
timestamp: [event timestamp]
windowNumber: [event windowNumber]
context: [event context]
eventNumber: [event eventNumber]
clickCount: [event clickCount]
pressure: [event pressure]];
// need to generate a new event otherwise selection of button
// after menu display fails
[NSMenu popUpContextMenu:[self menu] withEvent:newEvent forView:controlView];
return YES;
}
return [super trackMouse:event inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp];
}
Recently, I was trying to implement it and I came, as I think, with a simpler solution
-(IBAction)buttonClick:(id)sender {
NSButton * b = (NSButton*)sender;
NSPoint l = [ self.window convertBaseToScreen:b.frame.origin ];
[ self.menu popUpMenuPositioningItem:nil atLocation:l inView:nil ];
}
Update
convertBaseToScreen is deprecated starting from 10.7, instead of it use convertRectToScreen in the following way:
NSPoint l = [self.window convertRectToScreen:b.frame].origin;
Using a context menu on the action call isn't a great way to do it because the menu doesn't show until mouseUp - you don't get the hold & drag menu behavior. Apple's ButtonMadness sample shows how to really do this in a subclass of NSButton, see DropDownButton. https://developer.apple.com/library/mac/samplecode/ButtonMadness/Introduction/Intro.html
Summarizing that subclass: create a NSPopUpButtonCell with pullsDown set to YES & preferredEdge to NSMaxYEdge, copy your menu to add a blank top item and set it as that cell's menu, on mouseDown call [thePopUpCell performClickWithFrame:self.bounds inView:self] and set self.needsDisplay
Do like that.
-(IBAction)onClickSourceAdd:(id)sender {
NSMenu *mainMenu = [NSApp mainMenu];
NSMenu *sourceMenu = [[mainMenu itemAtIndex:2] submenu];
NSMenu *addMenu = [[sourceMenu itemAtIndex:0] submenu];
[NSMenu popUpContextMenu:addMenu
withEvent:[NSApp currentEvent]
forView:(NSButton *)sender];
}

Loop to check for the tag of a button

I am new to ObjC. I have a method in my controller class called
-(IBAction)playSound:(id)sender;
If I wanted to fill out the method by writing a for loop that checks the tag of each of my four buttons (already linked in storyboard), how would I do that? I am trying to make a button click play a sound. Please be descriptive in your answer.
-(IBAction)playSound:(id)sender
{
UIButton *button = (UIButton *)sender; // this is the button that has been pressed
if (button.tag == 0) {
// Play song for button 0
} else if (button.tag == 1) {
// Play song for button 1
} // ...
}
Or
-(IBAction)playSound:(id)sender
{
UIButton *button = (UIButton *)sender; // this is the button that has been pressed
NSString *songName = [songs objectAtIndex:button.tag]; // songs is an array
// Play song
}