Class Design for Delegates, Points, and Mouse Events

Here's a simplification:

I have an application with multiple buttons. If this is the first time the application is launched, I want to do something special. In my AppController class, which is an NSApp delegate, I use the -applicationDidFinishLaunching: delegate method to execute the test. After finding this is the first time, I first want to access some IBOutlets. Then I would like to receive mouse events for each button so that I can do other things.

I can't figure out what to do with the classes. I would like to create a new class (FirstLaunch) for the first launch, but I'm not sure what to call from the AppDelegate. Also, in order to receive mouse events, I don't have to subclass buttons, and given that I have multiple buttons, I'm confused. I could probably solve these problems one by one, but all together, they confuse me.

Crash, I need to access the IBOutlets that I have set in IB and detect when the buttons are clicked (and which button was clicked). I would like to be able to do this from another class so as not to clutter up the AppDelegate.

Thanks for the help!

To be clearer, what I am actually trying to do is use Matt Gemmel's MAAttachedWindow to trigger a help bubble using a button. When the button is clicked, the bubble disappears, and the other is somewhere else. The bubbles will be attached to controls in the main window.

0


a source to share


2 answers


Then I would like to be able to receive mouse events for each button so that I can do other things.

Don't worry about the mouse. There might not even be a mouse in there (think of the popular Mac tablet talk).

I would like to create a new class (FirstLaunch) for the first launch, but I'm not sure what to call from the AppDelegate.

This is where you create your own methods. You will probably make it singleton *; then you implement a method named like runFirstLaunchPanel:

, which will be an action method (more on that in a moment):

- (IBAction) runFirstLaunchPanel:(id)sender;

      

Instantiate the object in nib and then, from your application delegate, call the action method with nil

as the sender.

The reason to put an object in your nib and make the method an action method is that it makes it easier to connect a menu item to it so that the user can re-launch the panel with the first launch at a later time. (For example, if this is the Starting Points window, you can connect the New item to this action, rather than the default).

* Yes, I have seen articles about singles and I agree with them. In that case, it's okay

Also, to receive mouse events,

This is the wrong way to think about it. What you need to do is set your button to send a message to the controller to make the controller (maybe AppDelegate

) do something. The message you want to send is an action message.

Implement an action method on the object that owns the element that contains the window with buttons. Declare this method in the class header, then connect a button to it in IB by right clicking on your controller and dragging it from the correct circle of action methods onto the button.



This is called the target action paradigm, and it isolates the controller's responsibilities (doing things) from the views that ordered them. Since each action method only does one thing, you can have a button, menu item, and even another controller (application delegate above) send the same action message, and the receiving controller doesn't have to worry about which control the action is dispatched to, because that it already knows what it must do.

I shouldn't be a subclass of buttons,

No. You very rarely subclass anything other than NSObject (or for model objects in Core Data, NSManagedObject) in Cocoa.

Note that I said rarely, not never. You will need to subclass it separately, especially if you want to create custom or custom views and cells (and possibly custom windows). However, the subclass is not needed in Cocoa to the extent that (I hear) it is found in some other environments on other platforms.

and given that I have multiple buttons, I'm confused.

The Target Action Paradigm means that you don't need to create one subclass for each button. One controller class implements all the actions and stock buttons, because you hooked them up in IB, just tell the controller to "do it".

Failed, I need to access and manipulate the IBOutlets that I have installed in IB,

Probably not. At least not as much as you might think.

determine when buttons are pressed (and which button was pressed).

Nope. The buttons will worry about being pressed; you just worry about configuring them to send and then reply to their action messages.

0


a source


I am assuming you want to show some additional UI on first launch? If this is a separate window, then I would suggest creating a subclass NSWindowController

. Add a new NIB file to start the user interface for the first time in the project and change the File Owner object class to FirstLaunch

. Control-drag the wire from the File Owner delegate to the window to connect it to the output window

.

You create IBOutlet

by adding an instance variable to the class. If your application will only run on Leopard or higher, it is better to declare your stores like this:

@interface FirstLaunch : NSWindowController {
    NSTextField *myTextField;
}

@property (nonatomic, retain) IBOutlet NSTextField *myTextField;

@end

      

In Interface Builder, you will control the drag and drop of wires from the file owner to the control to associate with that receptacle. Make sure you release the reference to each IBOutlet

in your class dealloc

(unless you are using garbage collection), otherwise your application will leak memory.

Buttons send action messages when they are clicked, so you need to specify an action method for the button to invoke. You do this by declaring a method with a signature like this:



- (IBAction)myButtonClicked:(id)sender;

      

In the Builder interface, you can drag a wire from the button to your window controller and select a method myButtonClicked:

.

To do all of this, you need to instantiate a window controller and tell it to load the NIB file at runtime. So, in your class AppDelegate

, when you have determined that this is the first run, you will do the following:

FirstLaunch *firstLaunchController = [[FirstLaunch alloc] initWithWindowNibName:@"nameOfNibFile"];
[firstLaunchController show:self];

      

You probably want to store the reference to the window controller in an instance variable instead of a local variable as I did. And, depending on your application, it makes sense to show this as a sheet. But once you get it this far, you can figure out how to do it yourself.

+2


a source







All Articles