Change a button's background image programmatically in cocoa - objective-c

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 :)

Related

ios change background on button click

I so far only have the interface builder layout
I'm not clear on the syntax to reference all of these items from the layout
I know that IBOutlet has to be used somewhere, but I need a bit more handholding on what this objective C is doing. Nothing I've read tells me exactly why some declarations start with + and others with -
What I want to do is click a button in my layout, have a modal view pop up and change the background on the entire layout.
so the first step is referencing all these items I've made in the nib. help? (or post a link to more intuitive tutorials that you know about)
So you probably want to create an IBOutlet for your background view. Maybe it's a UIImageView that you can set it's image property based on what the user selects in the modal view. For this you would just declare the UIImageView you have in your IB file
UIImageView *imageView;
and then declare it as a property
#property (nonatomic,retain)IBOutlet UIImageView *imageView;
and synthesize it in your .m file
#synthesize imageView;
Don't forget to release it if you're not using ARC.
Then you can open up interface builder and if you click on your view controller File's Owner and go to the connections inspector you will see there is a new connection there for imageView. Just drag that connection over to your UIImageView in the IB file and that's it. You now have a reference in your code that connects to your UIImageView in IB.
That will allow you to set the UIImageView in your code by typing something like
self.imageView.image = [UIImage imageNamed:theNameTheUserJustPicked];
In order to get the modal view, you need an IBAction to trigger a method in your code so declare one like this in your .h file of your main nib.
- (IBAction)displayViewBackgroundChooser;
and then define it in your .m file.
- (IBAction)displayViewBackgroundChooser {
//present your new view on screen here
}
Then go back to interface builder and click on the File's Owner again. You should see it there in the connections inspector and then you can connect it to a button, for example, that would trigger that method.
Hope this helps to clear things up a bit on IBOutlets and IBActions.
You can make your UI elements created in IB interact with your code by means of IBOutlets and IBActions.
In your case, I would associate an action to the button, so that it is fired when the button is clicked; the action would open a modal view, and you could change the background of that view in the viewDidLoad method of the associated controller.
Here you find a video tutorial about adding an outlet. And here, the same about actions.
About your doubt on + and -, - identifies a normal method defined in a class; + defines a class method, i.e., a method that you can call on the class directly, without having to instantiate it first. Have a look at this S.O. article for more.

How can I make sure a window is only displayed once in Cocoa?

I have an NSWindow which contains an NSImageView. This window gets activated everytime I click on a cell in my tableview. I only want 1 instance of the NSWindow to appear, but want to be able to change the contents of NSImageView.
How can I initialize NSWindow and display only 1 instance of it?
This is a job for a singleton!
http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32
One possibility to do this is to create an NSWindowController subclass and an associated window XIB that gets loaded when the window controller is instantiated.
I'm sure you already have some controller class handling the mouse click in the NSTableView. In that class, simply keep around an instance of the NSWindowController subclass mentioned above as an instance variable. Whenever you need to display the window, tell that ivar to display its window.
If the window's contents are dependent on the clicked table cell, simply add some methods to the window controller that modify its window's contents and call these methods in your click-handling method before you display the window.
btw: I wouldn't use a singleton here because in this case it would just be a workaround for bad design (just my opinion, not a hard fact).

Should I use IB or Subclass UIView

So, I developed a kind of drop down button class.
Let's call it DDButton.
I mainly export one function :
-(void) addButtonWithImage:(UIImage*)image andTarget:(id)target andSelector:(SEL)selector
which lets the user add another button to the drop down.
I will need to use DDButton in different screens of my app.
I would like to use it like:
DDButton* ddb = [[DDButton alloc] initWithFrame:rect];
[ddb addButtonWithImage....]
[ddb addButtonWithImage....]
My question is since I never subclassed UIView before how should I implement it, and how should I use it later ?
Do I use IB and create a stub UIView which I'll connect to the DDButton in the Identity Pane ?
if so , how exactly I instantiate the view later on.
Or,
Do I subclass UIView ? if so , what methods I should override ? Do you I setup my buttons in the initializer ? in LayoutSubView ? In drawRect ?
I would love to hear the best approach here.
Thanks!
Edit
Let's say I choose the IB way : I have a main button which I set regardless of the
addButtonWithImage() calls, actually all calls to addButtonWithImage just "append" to that button. I want to main button to be the size of the view, until other buttons are added and then the view grows appropriately. However, I want the size of the view to be chosen by the user at first...using setFrame I guess.
Meaning in the awakeFromNib I can't count on the frame size yet (it only take the xib size I assume). So where would I setup my main button ? LayoutSubView ? setFrame ? I'm not sure.
Add your view to the interface in IB as a UIView, then change the class in the identity pane. If you need to do initialization in code, use a -(void)awakeFromNib method. I would suggest setting up the buttons when they are added in addButtonWithImage....
I'd probably do a subclass, building views in code is a good thing to learn.
Override drawrect: to do any custom drawing you need to do, if you're just adding a UIImageview or something and doing positioning you could just override initWith...: and do your custom initialisations.

Class Design for delegate, outlets, and mouse events

Here's a simplification:
I have an application with several buttons. If it is the first time the application is launching, I want to do some special things. In my AppController class, which is a delegate of NSApp, I use the delegate method -applicationDidFinishLaunching: to perform the test. After I've detected that it is the first time, I first want to access some IBOutlets. Then, I'd like to be able to get mouse events for each button, so that I can do other things.
I can't figure out want to do with the classes. I'd like to make a new class (FirstLaunch) for the first launch, but I'm not sure what to call from AppDelegate. Also, to get mouse events, shouldn't I be a sublass of the buttons, and considering that I have multiple buttons, I'm confused. I could probably tackle these issues one-by-one, but taken all together, they're confusing me.
Broken down, I need to access & manipulate IBOutlets I have set in IB, determine when buttons are clicked (and which button was clicked). I'd like to be able to do this from another class so as to not clutter up the AppDelegate.
Thanks for the help!
To be more clear, what I'm actually trying to do is to use Matt Gemmel's MAAttachedWindow to put up a help bubble by a button. When the button is clicked clicked, the bubble disappears and another one is put somewhere else. The bubbles will be attached to controls in the main window.
I'm guessing you want to show some additional user interface on the first launch? If it's a separate window, I'd advise creating a subclass of NSWindowController. Add a new NIB file for the first-run user interface to your project and change the class of the File's Owner object to FirstLaunch. Control-drag a wire from the File's Owner delegate onto the window to connect it with the window outlet.
You create IBOutlets by adding an instance variable to the class. If your app will only run on Leopard or higher, it's better to declare your outlets like this:
#interface FirstLaunch : NSWindowController {
NSTextField *myTextField;
}
#property (nonatomic, retain) IBOutlet NSTextField *myTextField;
#end
In Interface Builder, you'll control-drag a wire from the File's Owner onto the control to associate it with that outlet. Make sure that you release your reference to each IBOutlet in your class's dealloc method (if you're not using garbage collection) or else your app will leak memory.
Buttons send action messages when they're clicked, so you'll need to provide an action method for the button to call. You do that by declaring a method with a signature like this:
- (IBAction)myButtonClicked:(id)sender;
In Interface Builder, you'll control-drag a wire from the button onto your window controller and choose the myButtonClicked: method.
To make all this work, you'll need to create an instance of the window controller and tell it to load the NIB file at runtime. So, in your AppDelegate class, when you've determined that this is the first launch, you'll do this:
FirstLaunch *firstLaunchController = [[FirstLaunch alloc] initWithWindowNibName:#"nameOfNibFile"];
[firstLaunchController show:self];
You'll probably want to keep the reference to the window controller in an instance variable instead of a local variable like I've done here. And, depending on your application, it may make more sense to show this as a sheet. But once you've made it this far, you'll be able to figure out how to do that on your own.
Then, I'd like to be able to get mouse events for each button, so that I can do other things.
Don't worry about the mouse. There may not even be a mouse (think of the ever-popular tablet-Mac rumor).
I'd like to make a new class (FirstLaunch) for the first launch, but I'm not sure what to call from AppDelegate.
You make your own methods here. You'll probably make it a singleton*; then, you'll implement a method named something like runFirstLaunchPanel:, which will be an action method (more on those in a moment):
- (IBAction) runFirstLaunchPanel:(id)sender;
Instantiate the object in the nib, then, from your app delegate, call the action method with nil as the sender.
The reason to put the object in your nib and make the method an action method is that this makes it easy to hook up a menu item to it, so that the user can re-run the first-launch panel at a later time. (For example, if it's a Starting Points window, you might connect the New menu item to this action instead of the default one.)
*Yes, I've seen the articles about singletons, and I agree with them. In a case like this, it's OK.
Also, to get mouse events,
This is the wrong way of thinking about it. What you need to do is set your button up to send a message to your controller to make the controller (probably AppDelegate) do something. The message you want the button to send is an action message.
Implement an action method in the object that owns the nib containing the window with the buttons. Declare this method in the class's header, then connect the button to it in IB by right-clicking on your controller and dragging from the correct action method's circle to the button.
This is called the target-action paradigm, and it insulates controller responsibilities (doing things) from the views that ordered them. Because each action method does only one thing, you can have a button, a menu item, and even another controller (your app delegate, above) send the same action message, and the receiving controller won't have to care which control is sending the action, because it already knows what it has to do.
shouldn't I be a sublass of the buttons,
No. You very rarely create subclasses of anything other than NSObject (or, for model objects in Core Data, NSManagedObject) in Cocoa.
Note that I said “rarely”, not “never”. You will have to make the occasional subclass, especially if you want to create custom or customized views and cells (and, maybe, customized windows). However, subclassing is not necessary in Cocoa to the degree that (I hear) it is in some other frameworks on other platforms.
and considering that I have multiple buttons, I'm confused.
The target-action paradigm means you don't have to create one button subclass per button. One controller class implements all the actions, and the stock buttons, because you've hooked them up in IB, simply tell the controller “do this”.
Broken down, I need to access & manipulate IBOutlets I have set in IB,
Probably not. At least, not as much as you think you do.
determine when buttons are clicked (and which button was clicked).
Nope. The buttons will worry about being clicked; you just worry about setting them up to send, and then responding to, their action messages.

Accessing Views created in Interface Builder

I've created a ChildViewController class, and then a nib that uses that class.
Then I created a BaseView, that includes some buttons, and some text that I'll be changing programmatically.
Then I created two more views (Boy and Girl), that I want to be able to lay behind the baseview so that the background color is different along with some graphics in an ImageView. I've named the views that I created in IB 'Boy' and 'Girl'...
But when I go back to my code where I'm calling ChildViewController, I'm not sure how to access the views I created so I can call insertSubView. Do I need to instantiate them in code? (in ViewDidLoad perhaps?) Does the nib create the instances when it loads?
I'm confused about how to handle multiple views for a single ViewController
edit =================
#Pablo Santa Cruz
Your answer assumes that i have two nibs and two view controllers (one for each view). I want to know if I can use one nib and one controller, and load in UIViews. It seems silly to create another nib and controller, when all want to do is change the background color and some graphics. Can't I programatically load in UIViews into a UIViewController?
Add IBOutlets in your App Controller class in Xcode then link them in IB (ctrl-click or right-click) from the connections tab in the Inspector to the object.
Then you will be able to send method calls to the objects.
The code in Xcode should look like this:
#interface AppController : NSObject
{
IBOutlet Girl girlIvarName1;
IBOutlet Boy boyIvarName2;
}
#end
You can access a UIView programatically by assigning a value to its tag property, which can be set in IB on the first tab of the inspector (Command 1)
The tag value defaults to zero, so if you want to access it specifically, make it non zero and unique. e.g. 100, which I will use in the example code below
Once the tag is set you can access the view using the following code in your UIViewController that was initWithNibName for the NIB containing the tagged view
UIView *aView = [self.view viewWithTag:100];
You can get instances for your IBuilder views with this piece of code:
boyViewController = [[BoyViewController alloc] initWithNibName:#"BoyViewController" bundle:nil];
girlViewController = [[GirlViewController alloc] initWithNibName:#"GirlViewController" bundle:nil];
Assuming your NIB file names are BoyViewController and GirlViewController. With those instances, you can do whatever you need to. I.E., adding them to a parent view (with addSubView message on the parent).