How do I create an IBOutlet that is assigned to Multiple UIButtons - cocoa-touch

I have an IBOutlet assigned in my header file named *myButton and is type UIButton class.
the purpose of myButton is to programmatically assign the alpha to multiple buttons.
it seems as if you can only assign myButton to one button in IB.
is there a way to assign an alpha value to multiple buttons at the same time or am i going to have to refer to each button. ive got quite a few buttons and i need them all to change at the same time.
thanks for any help!

An IBOutlet is simply an instance variable (which is a pointer) in your class. You cannot have a pointer refer to more than one memory space simultaneously in any programming language.
You will need to refer to each button individually. You could look into storing pointers to all your buttons in an NSArray and simply iterating over it. You could also look into using an NSMatrixView or NSCollectionView to display your many buttons, and then take action on that to change all your buttons.

Related

Replacing NSTextField with NSScrollView to get a scrollbar

My OS X app written in Objective-C needs to display a varying NSString* variable theString which can get quite large.
I use Xcode IB to build a nib file which displays theString in a NSTextField* object panel declared inside AppDelegate.h like this:
#property (weak) IBOutlet NSTextField *panel;
Now I can set the contents of panel inside AppDelegate.m like this:
self.panel.stringValue = theString;
This all works fine. But I now want to give my text field a scrollbar. So in place of a "Text Field" I choose a "Text View" from the Object Library, and get its blue line to generate me a new declaration of panel which now looks like this:
#property (weak) IBOutlet NSScrollView *panel;
This now no longer works:
self.panel.stringValue = theString;
raising the error: (!) Property 'stringValue' not found on object of type 'NSScrollView*'
How do I need to fixup this statement?
(Might I just say I find the extensive Apple documentation on the topic byzantine and opaque. Why am I being naive to expect a simple answer to this simple question, as it all seems to imply? I must be missing something obvious -- what is it?)
What you got was a NSTextView wrapped inside a NSScrollView. The scrollView is the thing that makes the scrollbars you want. It basically holds a potentially much larger view inside its viewport and shows only small part of it, that you can shift around with the scroll bars. You need to get (another) reference from your code to the NSTextView inside the scrollView. You can find the NSTextView in the hierarchy in IB and attach to that.
This is in the direction of what you want but I think not quite what you need. The textView is a far more advanced control than a simple textField and probably more than you need. You could instead use a custom view by taking a NSScrollView that comes with a default NSView wrapped inside. Then instead of the NSTextView place your NSTextField on the NSView. The issue with this is that then you need to add some code to auto-resize the NSTextField and NSView based on the content of the textField. Once you got that sorted the scrollView will automatically arrange for the scrollbars that you need.

Change a button's background image programmatically in cocoa

All of the topics that I have searched are outdated or not complete in Obj-c.
I need to learn how to change a button's background image programmatically, when having the actual button in the InterfaceBuilder. (This sounds odd, but I need it for NSCollectionView as I have many similar button with different background images).
In the interface builder I drag a button onto my view window, what should I do after?
I understand that:
I need to create a NSButton Class
Connect the button from the interface builder to the code
Set the image
I have been struggling with this.
So did you connect the button to an IBOutlet property? If so then all you need to do is use [button setImage:]
If you haven't already done so, make sure the object instance that you want to change the image from is in interface builder, I.e has been dropped in as one of those blue boxes. Then if you set the object's class and have an IBOutlet property in the header file you can just drag the button outlet in the outlets tab (looks like an arrow) to the actual button itself to link the two
Edit: So it appears you're having trouble with the actual connecting part of the button? Chances are your IB file looks a bit like this:
Look for the objects section in the left hand list. These are the actual objects in your code that you can connect your button to. You might see an app delegate object there, which is included in the default IB file generated when you first create a project. If you want to handle the image changing in your app delegate, then simply add this property to your AppDelegate.h file to create an outlet:
#property IBOutlet NSButton *button;
If you go back to interface builder and select the app delegate object, you can see the outlet that you just created under the outlet tab:
Drag the little circle thing to the button to connect it, that should be the easiest bit.
But I'm going to just presume that you want to call it from somewhere else other than your app delegate, and for that we'll need to do some more explaining. If the class you want to call it from is a subclass of NSView and is already in your interface builder, you can just add that line to your view's header file and it will appear under the view's outlet tab.
If you want to call this from another object that isn't a view or such, you'll need to do either two options:
Create the object instance in interface builder. This means that instead of creating in normally with alloc] init]; etc. you'll have to actually drag in an object into interface builder. This can change the structure of your object quite a bit as you'll no longer be able to create it at will, since it will automatically be instantiated whenever you load your .nib file. Also important to note is that your init function will not be called anymore and you'll need to use awakeFromNib instead. If you do choose to go down this route, just drag over an object:
Add your outlet property to the header file:
Set the object's class:
And connect the outlet:
If making objects XIB loaded just isn't your thing, you can always just connect the property outlet to your app delegate/view controller and access it from that instead. Hopefully this clears things up, if this was the problem you were having.
For iOS:
Don't need to create a NSButton subclass.
You only need to add button on Storyboard, set the IBOutlet property for your button (ctr+drag from your button to your view controller), and set the background image with:
[myButton setBackgroundImage:[UIImage imageNamed:#"ImageName"] forState:UIControlStateNormal]
For MacOS:
You can use
setImage:
as describe on Apple Doc, and changes its size/position
(Sorry for my bad English)
ofcourse as Duukee Said,i think no need to create any NSButton Or UIButton Instances Manually When We have an object in Interface Builder,We can just use it's outlet as follows,
UIImage* Desired_Image=[UIImage imageNamed:#"yourimage.png"];
[My_Button setimage:Desired_Image forState:UIcontrolstateNormal];
HTH!Happy Coding :)

Unable to disable Checkbox (NSButton) inside a disabled NSTableView

I have an app that contains an NSTableView instance with 2 columns. One column, is an instance of this:
#import <Cocoa/Cocoa.h>
#class NSTableView;
#interface MMCheckboxTableCellView : NSTableCellView
#property (weak) IBOutlet NSButton *checkboxField;
#end
and the implementation is all boilerplate with no custom code added at all. In code, the NSTableView instance sets tableview.enabled = YES (or NO) programmatically based on various state of the app. When tableview is disabled, the other column of the table, which is display only, stops responding to click actions, as expected. The checkbox column, above, continues to respond to clicks and lets the user check/uncheck the button instances.
To try to troubleshoot this, I added a Text Field (it's not hooked up to anything) in the the checkbox column and when the tableview is disabled, it isn't possible to enter text into the field. Is there something special about NSButton that I'm missing? Is it possible that because I derived this class from NSTableCellView with an added Check Box rather than using a Check Box Cell I'm running into this problem?
I finally figured this out. It appears that even though the NSButton is embedded in the NSTableView, setting enabled=NO on the table doesn't control the behavior of the button. The only thing that eventually made this work was to invoke setEnabled the the control based on the state of the app. This had to happen in the rendering of the cell, so when the state changes, it was also necessary to invoke NSTableView:reloadData so the visible cells would redraw immediately.
As an alternative, I decided to work around this same problem by setting up a computed property matching to my boolean property that returned either a blank or a checkmark character (✓). Then bound to this field as a normal NSTextfield for which the enabling/disabling works.
// Swift
// Computed variables on model for readonly display in table
var bIosText:String {return bIos ? "✓" : " " }
var bAndroidText:String {return bAndroid ? "✓" : " " }
Looks pretty good I think:
Of course this is only part of the solution, if you want to enable editing, you need to have multiple columns and hide/unhide as needed.
Do not embed an NSButton in the table view, only use a NSButtonCell. If your NSTableView was view based, it will switch to cell based (at least Xcode did that for me).
So this is wrong:
And this is right:
It should suffice to disable/enable the table view after this change, the button cell will behave accordingly.

When should I use an IBOutlet instead of an IBAction?

I know the differences between IBAction and IBOutlet, but I don't know when I should use one over the other.
For example, I'm trying to make a calculator. I have ten buttons and one label to display a result. Must I create ten IBOutlets in my interface? If not, why not?
An IBOutlet is a connection to an object, and an IBAction is a connection to a method to be invoked as a callback. For example, you might have ten buttons and one label, but you might connect to the label using an IBOutlet (so you can update its value), and a single function - (IBAction)buttonPressed:(id)sender; that is connected to the onTouchUpInside event of each of the ten buttons. The buttonPressed: method's implementation will then need to inspect the sender to figure out what its value is.
You should not need to have an IBOutlet for each button if this is all you need to do.
Ok, IBOutlets and IBActions serve two separate purposes.
IBActions are basically methods that can be connected to UI elements through IB. They provide ways for your object to be notified when something has happened with the UI. They also provide the sender argument when they are called so that you can access the UI Element that sent the message from within the method.
An IBOutlet on the other hand offers a way to get a reference to the UI element within your code at any point, it is used when you need to change aspects of the UI.
For your situation you don't really need to have IBOutlets for the buttons because you don't need to change anything about them, you just need to be notified when they have been pressed.
As a note, if you have that many buttons, and you for some reason needed a way to access them from within your code to change something about them i would not recommend using 10 IBOutlets. Instead, i would use the viewWithTag: method, and set each buttons tag accordingly so that you don't have to go to the trouble of creating IBOutlets for each one.
In your case, I would create one IBOutlet for the label, and one IBAction for the buttons. The IBOutlet for the label would be to update the text when the user pressed a button. Your IBAction would look something like this:
-(IBAction)digitPressed:(UIButton *)sender{
//First you have to check if there is currently any text in the label
//If there is not, the below line of code is performed
NSString *textWithDigit = [[yourLabel.text] stringByAppendingString: sender.titleLabel];
//This line updates the label's text
label.text = textWithDigit;
}
I only put in the code relevant to IBActions and IBOutlets (you need an IBOutlet for the label in order to update the text, and you need the IBAction to change the label's text to the digit pressed); there is much more code needed (code needed to check if the user is currently in the middle of typing a number, code for operations like +, -, *, /), but this was just a start.
Hope this helps!

Array of NSButton

I wonder if I can do something like
IBOutlet NSButton * aButton[100];
It turns out that aButton cannot be seen in the interface builder.
My app has lots of buttons and I want to see if there are way I can use looping to iterate the state of all buttons.
IB doesn't handle arrays. You can add them using a loop in your code instead.
You may find an NSMatrix of NSButtonCells easier to work with, and unlike a C array of NSButtons, you can create one in IB.
No, you can't use an array as an outlet. Some options:
create a NSButton subclass
that does what you want to do
walk the view hierarchy at runtime to
find the buttons
OTOH, if your UI has 100 buttons, you've probably got bigger problems...