UPDATED: I'm now overriding the NSView keyUp method from a NSView subclass set to first responder like below, but am still not seeing evidence that it is being called.
#implementation svsView
- (BOOL)acceptsFirstResponder {
return YES;
}
- (void)keyUp:(NSEvent *)event {
//--do key up stuff--
NSLog(#"key up'd!");
}
#end
--ORIGINAL POST--
I'm new to Cocoa and Obj-C and am trying to do a (void)keyUp: from within the implementation of my controller class (which itself is of type NSController). I'm not sure if this is the right place to put it, though. I have a series of like buttons each set to a unique key equivalent (IB button attribute) and each calls my (IBAction)keyInput method which then passes the identity of each key onto another object. This runs just fine, but I also want to track when each key is released.
--ORIGINAL [bad] EXAMPLE--
#implementation svsController
//init
//IBActions
- (IBAction)keyInput:(id)sender {
//--do key down stuff--
}
- (void)keyUp:(NSEvent *)event {
//--do key up stuff--
}
#end
Upon fail, I also tried the keyUp as an IBAction (instead of void), like the user-defined keyInput is, and hooked it up to the appropriate buttons in Interface Builder, but then keyUp was only called when the keys were down and not when released. (Which I kind of figured would happen.)
Pardon my noobery, but should I be putting this method in another class or doing something differently? Wherever it is, though, I need it be able to access objects owned by the controller class.
Thanks for any insight you may have.
NSResponder subclasses (such as a custom subclass of NSView) handle key events. They even handle more abstract-level events such as "move left/right", "insert newline", etc. They can then send a message to a controller to respond accordingly.
Wow! I think I've nailed it. I just needed to instantiate my subclass with a NSView/NSWindow reference to the class in IB. Wasn't actually creating an instance of it in the UI. The past several hours down the crapper! Sans that I learned a thing or two along the way. ;)
Related
I have my viewcontroller class for my only current View and another class with static methods for my mathematical logic. ViewController class has an IBOutlet for a label. How can I reference this outlet from within the functions of my Logic class?
You could pass a pointer to the logic class just like any other variable, but I wouldn't recommend directly accessing the IBOutlet property.
What I'd recommend, is either having the logic class return the values and have the controller update the label as needed, or if it involves background processing that doesn't return immediately, use the delegate pattern. This way, the logic class will inform the controller when the data is ready, or the calculations are finished, and then the controller can update the UI as needed.
Look into iOS Protocols to define the structure of a delegate class :)
You shouldn't allow your Logic class to access a UI control because it does not follow the Model-View-Controller pattern, which is a smart way to keep your code organized so that it's easier to follow as your project becomes more complicated. Instead, you would want your ViewController to communicate between the UI and the Logic class for you.
For example, if you had a Calculate button at the bottom of your view that the user taps, the tap should be handled by the ViewController. The ViewController would call a function in your Logic class that might return a value. Then the ViewController would take that value and set it as the text of the label. Here's a snippet of code that illustrates the idea:
- (IBAction) calculateSomeValue: (id) sender {
int result = [Logic calculateValue];
[self.label setText: [NSString stringWithFormat: #"Your result is: %d", result]];
}
I have an NSTableView and I have some issues with its default behavior.
If I've overridden the keyDown: method in a category as follows:
- (void) keyDown:(NSEvent *)event {
[super keyDown:event];
}
I can't change the row selection with the keyboard arrow keys anymore. Why is that?
in a category of NSTableView.
In a category of NSTableView, super refers to NSTableView's superclass (NSControl), not to NSTableView as it would in a subclass. You're passing the event on to the NSControl version of keyDown:, which knows nothing about table views and can't handle the arrow keys the way you want.
If you override a method in a category, there's no way to call the original method. It's almost never a good idea to do this on framework classes (whose source is unavailable to you). Use a subclass.
Cf. Using Super in an Objective C Category? and Is calling super in a category the same as calling it in a subclass?
I know this question has been asked a lot before, but nothing will work for me. The following code will not do anything at all.
- (void) mouseDown:(NSEvent*)event {
NSLog(#"It worked!");
}
I have tried a lot of different methods to get this to work, including creating custom NSEvents in this way:
NSEvent *someEvent;
- (void) mouseDown:(NSEvent*)someEvent {
NSLog(#"It worked!");
}
This is my .h file:
#interface test : NSWindow <NSWindowDelegate> {
}
Would somebody explain how to make this do something?
Make sure your class inherits from NSWindow and conforms to the <NSWindowDelegate> protocol. Otherwise, that's just a method that happens to be named mouseDown, and nobody will ever call it.
Update: Change your header file so that it looks like this:
#interface test : NSWindow <NSWindowDelegate> {
}
In other words, don't put a prototype of mouseDown inside the interface definition, or anywhere else in the .h file.
In your implementation file (.m) put just the method:
- (void) mouseDown:(NSEvent*)someEvent {
NSLog(#"It worked!");
}
Assuming that you have logging turned on in the device (are you sure you can read NSLog output from elsewhere in your program?), you should see "It worked!" printed there.
I'm not an obj-C expert by any means, but I think by putting the mouseDown prototype inside the interface definition, you were basically creating your own custom mouseDown method which hid the "real" one. This indicated to the compiler that it should not call your mouseDown method on a window click.
Your subclass must have a parent class of NSResponder, otherwise you will not get any events.
You're overriding the NSWindow class, you should be overriding the NSView "contentView" of the NSWindow class to capture mouse events. Most of the decorations (NSViews) on the window outside of the contentView are private.
Just create a new NSView that overrides mouseDown, etc and add it as your content view to the NSWindow object.
I know this question has been asked a lot before, but nothing will work for me. The following code will not do anything at all.
- (void) mouseDown:(NSEvent*)event {
NSLog(#"It worked!");
}
I have tried a lot of different methods to get this to work, including creating custom NSEvents in this way:
NSEvent *someEvent;
- (void) mouseDown:(NSEvent*)someEvent {
NSLog(#"It worked!");
}
This is my .h file:
#interface test : NSWindow <NSWindowDelegate> {
}
Would somebody explain how to make this do something?
Make sure your class inherits from NSWindow and conforms to the <NSWindowDelegate> protocol. Otherwise, that's just a method that happens to be named mouseDown, and nobody will ever call it.
Update: Change your header file so that it looks like this:
#interface test : NSWindow <NSWindowDelegate> {
}
In other words, don't put a prototype of mouseDown inside the interface definition, or anywhere else in the .h file.
In your implementation file (.m) put just the method:
- (void) mouseDown:(NSEvent*)someEvent {
NSLog(#"It worked!");
}
Assuming that you have logging turned on in the device (are you sure you can read NSLog output from elsewhere in your program?), you should see "It worked!" printed there.
I'm not an obj-C expert by any means, but I think by putting the mouseDown prototype inside the interface definition, you were basically creating your own custom mouseDown method which hid the "real" one. This indicated to the compiler that it should not call your mouseDown method on a window click.
Your subclass must have a parent class of NSResponder, otherwise you will not get any events.
You're overriding the NSWindow class, you should be overriding the NSView "contentView" of the NSWindow class to capture mouse events. Most of the decorations (NSViews) on the window outside of the contentView are private.
Just create a new NSView that overrides mouseDown, etc and add it as your content view to the NSWindow object.
I'm a little confused about raising an event in Objective-C,
I came from C# (.NET) environment and I would like to learn Objective-c and Cocoa programming.
So here's my question:
I have a little application with a NSTextField that I want to use to listen to an event.
What I want to do : When I double click within this control, it raise an event and pop up ex: an NSAlert that displays "Double clicked".
So how can I do that, I'am a visual person so I need some code exemple to show how it's work; Like what should I put within the .h class and within the .m class.
Thanks in advance,
Alex.
You need to read up on the Cocoa Fundamentals and the target/action mechanism. An NSControl (like its NSButton subclass) has a target to which it sends an action with itself as the sender. Not all controls support -doubleAction, but some do.
NSButton/NSButtonCell does not support a double action, so you would need to do some subclassing and override the mouse methods. NSEvent (which is passed into mouse methods) can be queried for its click count to distinguish double-clicks from singles.
Just for the record, it's usually click-and-hold that produces a context menu on OS X and this capability is announced through a down-facing arrow somewhere on the right of the button face. Few people will actually know a menu is there for double-clicking and it's hard to represent this with a symbol on the button face. Consider a click-and-hold trigger for your button's context menu.
I am not sure why you want to do this in a text field, but here is how to do it:
You need to use a subclass that overrides click behavior for double clicks. The header file would look like this:
#import <Cocoa/Cocoa.h>
#interface ClassName : NSTextField {
//Any new instance variables here
}
//Any new methods here
#end
and the implementation file would look like this:
#import "ClassName.h"
#implementation ClassName
- (void)mouseUp:(NSEvent *)event {
//You can also do this with mouseDown:, depending on when you prefer to handle the event
if([event clickCount] == 2) {
//Handle double click here
} else [super mouseUp:event]; //or pass to parent implementation
}