NSWindow doesn't receive keyboard events - objective-c

I creating NSWindow programmatically and i can't receive any keyboard messages. Instead of this i typing in Xcode editor, but my window is in focus at this time. How i can intercept this events?
Here is my code:
//// delegate
#interface MyDelegate : NSObject
#end
#implementation MyDelegate
#end
//// view
#interface MyView : NSView
#end
#implementation MyView
- (BOOL)isOpaque { return YES;}
- (BOOL)canBecomeKeyView { return YES;}
- (BOOL)acceptsFirstResponder { return YES;}
- (void)keyDown:(NSEvent *)event
{
printf("PRESS\n"); // it's ignoring
}
#end
//// main
int main(int argc, const char **argv){
[NSApplication sharedApplication];
NSWindow *window = [[NSWindow alloc]
initWithContentRect:NSMakeRect( 0, 0, 100, 100 )
styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask
backing:NSBackingStoreBuffered
defer:NO];
[window setContentView: [[MyView alloc] init]];
[window setDelegate: [[MyDelegate alloc] init] ];
[window setAcceptsMouseMovedEvents:YES];
[window setLevel: NSFloatingWindowLevel];
[window makeKeyAndOrderFront: nil];
[NSApp run];
return 0;
}

You need to make the application a foreground application. This is required for the main window to receive key events.
ProcessSerialNumber psn = {0, kCurrentProcess};
OSStatus status =
TransformProcessType(&psn, kProcessTransformToForegroundApplication);

Related

I can't write text to NSTextField Objective C

I've spent much time finding an answer but I don't understand how right it googling.
I just need to create a simple text field. I've done it but I can't write some text.
After build and run I tried to write but the text was written in x-code window.
What's wrong?
I guess it's related to focus NSWindow or NSApplication.
It's very strange because I can call the context menu and I see cut/copy/paste functions. I even can use those but I can write text by the keyboard.
All code already in main.m
#include <Cocoa/Cocoa.h>
#interface Window : NSWindow {
NSTextField* textBox1;
NSTextField* textBox2;
}
- (instancetype)init;
- (BOOL)windowShouldClose:(id)sender;
#end
#implementation Window : NSWindow
- (instancetype)init {
NSTextField* textBox1 = [[[NSTextField alloc] initWithFrame:NSMakeRect(10, 270, 100, 20)] autorelease];
[textBox1 setStringValue:#"textBox1"];
NSTextField* textBox2 = [[[NSTextField alloc] initWithFrame:NSMakeRect(10, 230, 100, 20)] autorelease];
[textBox2 setStringValue:#"textBox2"];
[super initWithContentRect:NSMakeRect(100, 100, 300, 300)
styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable | NSWindowStyleMaskUnifiedTitleAndToolbar
backing:NSBackingStoreBuffered
defer:NO];
[self setTitle:#"TextBox Example"];
[[self contentView] addSubview:textBox1];
[[self contentView] addSubview:textBox2];
[self makeFirstResponder:textBox2];
[self setIsVisible:YES];
return self;
}
- (BOOL)windowShouldClose:(id)sender {
[NSApp terminate:sender];
return YES;
}
#end
int main(int argc, char* argv[]) {
[[[Window alloc] init] autorelease];
NSApplication *application = [NSApplication sharedApplication];
[application activateIgnoringOtherApps:YES];
[NSApp run];
}
Thank you for your help but it didn't help me... :(
I could resolve my problem.
I just added the method call setActivationPolicy.
int main(int argc, char* argv[]) {
[[[Window alloc] init] autorelease];
NSApplication *application = [NSApplication sharedApplication];
[application activateIgnoringOtherApps:YES];
[application setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp run];
}

How do I create a modal sheet window exclusively by programming

How do I create a modal sheet window exclusively by programming. Interface builder seems to me over the hand, I'm at the beginning and I want to learn programming, not how I arrange some elements graphically.
I've heard on several programmers that is possible.
I tried without success:
#interface AppDelegate : NSObject <NSApplicationDelegate> {
NSWindow* mywindow;
NSButton* button;
IBOutlet NSPanel* theSheet;
}
- (void) buildWnd;
#end
#implementation AppDelegate
- (void) buildWnd {
button = [[[NSButton alloc] initWithFrame:NSMakeRect(50, 225, 90, 25)] autorelease];
[button setTitle:#"button"];
[button setTarget:self];
[button setAction:#selector(OnbuttonClick:)];
[button setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
mywindow = [[NSWindow alloc] initWithContentRect: NSMakeRect(100, 100, 700, 500) styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable backing: NSBackingStoreBuffered defer: NO];
[mywindow center];
[mywindow setTitle:#"Sheet example"];
[[mywindow contentView] addSubview:button];
[mywindow setIsVisible:YES];
}
- (IBAction) showTheSheet:(id)sender {
}
-(IBAction) endTheSheet:(id)sender {
[mywindow endSheet: theSheet];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildMenu];
[self buildWnd];
}
- (void) applicationDidFinishLaunching: (NSNotification *)notification {
}
- (IBAction) OnButtonClick:(id)sender {
NSLog(#"OnButtonClick");
[mywindow beginSheet: theSheet
completionHandler:^(NSModalResponse returnCode) {
[NSApp stopModalWithCode: returnCode];
}];
[NSApp runModalForWindow: theSheet];
}
#end
int main() {
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}
I receive this error message: AppDelegate OnbuttonClick: unrecognized selector sent to instance.
Where I'm wrong please?
You neglected to set up the sheet. This example should run in Xcode by replacing the main.m with the code below and deleting the pre-supplied AppDelegate files:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
NSPanel *sheet;
}
- (void) buildWnd;
#end
#implementation AppDelegate
- (void) showBtnAction:(id)sender {
[window beginSheet: sheet completionHandler:^(NSModalResponse returnCode) {
[NSApp stopModalWithCode: returnCode];
}];
[NSApp runModalForWindow: sheet];
}
-(void) hideSheet:(id)sender {
[window endSheet: sheet];
}
- (void) buildWnd {
window = [[NSWindow alloc] initWithContentRect: NSMakeRect(100, 100, 700, 500) styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable backing: NSBackingStoreBuffered defer: NO];
[window center];
[window setTitle:#"Sheet example"];
[window setIsVisible:YES];
// **** Sheet Panel **** //
sheet = [[NSPanel alloc] initWithContentRect:NSMakeRect( 0, 0, 500, 450 )
styleMask:NSWindowStyleMaskDocModalWindow backing:NSBackingStoreBuffered defer:YES];
[sheet center];
[sheet setTitle:#"NSPanel"];
// **** OK Button on Sheet **** //
NSButton *okayBtn = [[NSButton alloc] initWithFrame:NSMakeRect(50, 225, 50, 25)];
[okayBtn setTitle:#"OK"];
[okayBtn setBezelStyle:NSBezelStyleRounded ];
[okayBtn setTarget:self];
[okayBtn setAction:#selector(hideSheet:)];
[[sheet contentView] addSubview:okayBtn];
// **** Show Button **** //
NSButton *showBtn = [[NSButton alloc] initWithFrame:NSMakeRect(50, 225, 150, 25)];
[showBtn setTitle:#"Show sheet"];
[showBtn setBezelStyle:NSBezelStyleRounded ];
[showBtn setAction:#selector(showBtnAction:)];
[showBtn setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[[window contentView] addSubview:showBtn];
// **** Quit btn **** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect(650, 5, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular ];
[quitBtn setTitle: #"Q" ];
[quitBtn setAutoresizingMask: NSViewMinXMargin];
[quitBtn setAction:#selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildWnd];
}
- (void) applicationDidFinishLaunching: (NSNotification *)notification {
}
#end
int main() {
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}

How to add stoplight buttons to an OS X application programmatically

I'm building an OS X cocoa application and I'm not using interface builder (for a variety of reasons). I've got the application to the point of loading a menu, title bar and main window, but I can't seem to figure out how to add the stoplight buttons to the title bar (programmatically).
My AppDelegate.m looks like this:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
MainViewController *mVC = [MainViewController new];
[mVC showMainViewController];
}
Then code in the MainViewController then creates the menu, window, and loads the application, as follows:
//
// MainViewController.m
// TestApp
//
#import "MainViewController.h"
#implementation MainViewController
#synthesize menubar;
#synthesize appMenu;
#synthesize appMenuItem;
#synthesize quitMenuItem;
#synthesize appName;
#synthesize quitTitle;
#synthesize window;
#synthesize homeViewController;
#synthesize resolutionHeight;
#synthesize resolutionWidth;
#synthesize width;
#synthesize height;
- (id)init
{
self = [super init];
if (self) {
appName = #"TestApp";
[self setupMenubar];
[self setupMainWindow];
}
return self;
}
- (void)setupMenubar
{
// Set up the main menu
menubar = [NSMenu new];
appMenu = [NSMenu new];
appMenuItem = [NSMenuItem new];
quitTitle = [NSString stringWithFormat:#"Quit %#", appName];
quitMenuItem = [[NSMenuItem alloc] initWithTitle:quitTitle
action:#selector(terminate:)
keyEquivalent:#"q"];
[menubar addItem:appMenuItem];
[appMenu addItem:quitMenuItem];
[appMenuItem setSubmenu:appMenu];
[NSApp setMainMenu:menubar];
}
- (void)setupMainWindow
{
// set the dimensions of the application
resolutionWidth = [[NSScreen mainScreen] frame].size.width;
resolutionHeight = [[NSScreen mainScreen] frame].size.height;
width = resolutionWidth * 0.75;
height = resolutionHeight * 0.75;
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height)
styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered defer:NO];
[window cascadeTopLeftFromPoint:NSMakePoint(10, 10)];
// add window buttons
closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSTitledWindowMask];
// set metadata for the window
[window setTitle:appName];
[window makeKeyAndOrderFront:nil];
}
- (void)showMainViewController
{
// Set app settings
[NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp activateIgnoringOtherApps:YES];
[NSApp run];
}
#end
I've looked around and I'm kind of at a loss for how to proceed.
You might try changing your NSWindow init method to the following:
window = [[NSWindow alloc]
initWithContentRect:NSMakeRect(0, 0, width, height)
styleMask:NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask
backing:NSBackingStoreBuffered defer:NO];
I believe that ORing in the additional masks automatically adds the corresponding buttons to the title bar for you: NSClosableWindowMask adds the close button, NSMiniaturizableWindowMask adds the minimize (center) button, and NSResizableWindowMask adds the zoom (rightmost) button.

keyDown not being called

I have a custom NSView called SurfaceView. It is the contentView of a NSWindow and it handles basic events like mouse click and drawing. But don't matters what I do, it does not handle the keyDown function. I've already override the acceptsFirstResponder but nothing happens.
If it matters, I run the application using a custom NSEvent loop, shown below:
NSDictionary* info = [[NSBundle mainBundle] infoDictionary];
NSString* mainNibName = [info objectForKey:#"NSMainNibFile"];
NSApplication* app = [NSApplication sharedApplication];
NSNib* mainNib = [[NSNib alloc] initWithNibNamed:mainNibName bundle:[NSBundle mainBundle]];
[mainNib instantiateNibWithOwner:app topLevelObjects:nil];
[app finishLaunching];
while(true)
{
NSEvent* event = [app nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate date] inMode:NSDefaultRunLoopMode dequeue:YES];
[app sendEvent:event];
// Some code is execute here every frame to do some tasks...
usleep(5000);
}
Here's the SurfaceView code:
#interface SurfaceView : NSView
{
Panel* panel;
}
#property (nonatomic) Panel* panel;
- (void)drawRect:(NSRect)dirtyRect;
- (BOOL)isFlipped;
- (void)mouseDown:(NSEvent *)theEvent;
- (void)mouseDragged:(NSEvent *)theEvent;
- (void)mouseUp:(NSEvent *)theEvent;
- (void)keyDown:(NSEvent *)theEvent;
- (BOOL)acceptsFirstResponder;
- (BOOL)becomeFirstResponder;
#end
--
#implementation SurfaceView
#synthesize panel;
- (BOOL)acceptsFirstResponder
{
return YES;
};
- (void)keyDown:(NSEvent *)theEvent
{
// this function is never called
};
...
#end
Here's how I create the view:
NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(left, top, wide, tall) styleMask:NSBorderlessWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask backing:NSBackingStoreBuffered defer:NO];
...
[window makeKeyAndOrderFront:nil];
SurfaceView* mainView = [SurfaceView alloc];
[mainView initWithFrame:NSMakeRect(0, 0, wide, tall)];
mainView.panel = panel;
[window setContentView:mainView];
[window setInitialFirstResponder:mainView];
[window setNextResponder:mainView];
[window makeFirstResponder:mainView];
I found out what was preventing the keyDown event from being called. It was the NSBorderlessWindowMask mask, it prevents the window from become the key and main window. So I have created a subclass of NSWindow called BorderlessWindow:
#interface BorderlessWindow : NSWindow
{
}
#end
#implementation BorderlessWindow
- (BOOL)canBecomeKeyWindow
{
return YES;
}
- (BOOL)canBecomeMainWindow
{
return YES;
}
#end
In addition to answer: Check in your IB checkbox for NSWindow.
Title Bar should be checked. It the similar to NSBorderlessWindowMask
In my case I had to override the keyDown method on both NSView and NSWindow (created a customization of both). In the NSWindow in the keyDown override I had to call
- (void) keyDown:(NSEvent *) event {
if (self.firstResponder != self) {
[self.firstResponder keyDown:event];
}
}
to let the event reach the view. Of course I had also to call makeFirstResponder first on the NSWindow and pass the contentView to it :
[window makeFirstResponder: [window contentView] ];

Trying to understand how to use xib files

I have a custom view that I'm using in a xib file. I load the view and add it to a window. It adds the view just fine as I can see the default text of the labels in the view, but when I try to change the label with a method call, it doesn't change the text.
The custom view isn't anything to fancy, just draws a rounded, transparent background.
NotificationView.h
#import <Cocoa/Cocoa.h>
#interface NotificationView : NSView
#property (weak) IBOutlet NSTextField *primaryLabel;
#property (weak) IBOutlet NSTextField *secondaryLabel;
#property (weak) IBOutlet NSTextField *identifierLabel;
#end
NotificationView.m
#implementation NotificationView
#synthesize primaryLabel;
#synthesize secondaryLabel;
#synthesize identifierLabel;
- (id) initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
if (self)
{
return self;
}
return nil;
}
- (void)drawRect:(NSRect)dirtyRect
{
NSColor *bgColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.6];
NSRect rect = NSMakeRect([self bounds].origin.x + 3, [self bounds].origin.y + 3, [self bounds].size.width - 6, [self bounds].size.height - 6);
NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:5.0 yRadius:5.0];
[path addClip];
NSShadow *shadow = [[NSShadow alloc] init];
[shadow setShadowColor:[NSColor redColor]];
[shadow setShadowBlurRadius:2.0f];
[shadow setShadowOffset:NSMakeSize(0.f, -1.f)];
[shadow set];
[bgColor set];
NSRectFill(rect);
[super drawRect:dirtyRect];
}
#end
In the xib I have a custom view set to the type NotificationView. I've added 3 labels to the view and connected them to the above IBOutlets. (I ctrl-click & drag from the label to the .h file to make the connection.)
I'm loading the view and adding it to a window with the following method. It looks through an array of windows, if an existing match is found it used that window, if not it creates a new window.
- (void) popupNotificationWithTag:(NSString *)tag fade:(double)msFade lineOne:(NSString *)lineOneText lineTwo:(NSString *)lineTwoText
{
NotificationWindow *notificationWindow;
NotificationWindow *tmpWindow;
NSEnumerator *enumerator;
// Walk the notification windows in the array
enumerator = [self.notificationWindows objectEnumerator];
if(enumerator)
{
while((tmpWindow = [enumerator nextObject]))
{
if([tmpWindow.tag isEqualToString:tag])
{
notificationWindow = tmpWindow;
}
}
}
// Make a new notification window
if (!notificationWindow)
{
int width = [[NSScreen mainScreen] frame].size.width;
int height = [[NSScreen mainScreen] frame].size.height;
notificationWindow = [[NotificationWindow alloc] initWithRect:NSMakeRect(width - 420, height - 130, 400, 100)];
NSNib *nib = [[NSNib alloc] initWithNibNamed:#"Notification" bundle: nil];
NSArray *objects;
[nib instantiateNibWithOwner:self topLevelObjects:&objects];
for (id obj in objects) {
if ([[obj class] isSubclassOfClass:[NSView class]])
[notificationWindow setContentView:obj];
}
[notificationWindow setTag:tag];
[self.notificationWindows addObject:notificationWindow];
}
// Display window
[notificationWindow makeKeyAndOrderFront:nil];
[notificationWindow display];
notificationWindow.fadeOut = msFade;
[notificationWindow setPrimaryText:lineOneText];
[notificationWindow setSecondaryText:lineTwoText];
[notificationWindow setIdentifierText:tag];
}
The window class is NotificationWindow.h
#import <Foundation/Foundation.h>
#interface NotificationWindow : NSWindow
#property (nonatomic, strong) NSString *tag;
#property (nonatomic) double fadeOut;
- (id)initWithRect:(NSRect)contentRect;
- (void) setPrimaryText:(NSString *)text;
- (void) setSecondaryText:(NSString *)text;
- (void) setIdentifierText:(NSString *)text;
#end
NotificationWindow.m
#import "NotificationWindow.h"
#import "NotificationView.h"
//===========================================================================================================================
// Private call properties and methods
//===========================================================================================================================
#interface NotificationWindow()
#property (nonatomic,strong) NSTimer *timerFade;
- (void) timerFadeFired;
#end
//===========================================================================================================================
//===========================================================================================================================
#implementation NotificationWindow
//===========================================================================================================================
// Property Getters and Setters
//===========================================================================================================================
#synthesize tag = _tag;
#synthesize fadeOut = _fadeOut;
#synthesize timerFade = _timerFade;
//===========================================================================================================================
// Public methods
//===========================================================================================================================
- (id)initWithRect:(NSRect)contentRect
{
if (self = [super initWithContentRect:contentRect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO]) {
[self setLevel: NSScreenSaverWindowLevel];
[self setBackgroundColor: [NSColor clearColor]];
[self setAlphaValue: 1.0];
[self setOpaque: NO];
[self setHasShadow: NO];
[self setIgnoresMouseEvents: YES];
[self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces];
[self orderFront: NSApp];
self.fadeOut = -1;
// Start our timer to deal with fadeing the window
self.timerFade = [NSTimer scheduledTimerWithTimeInterval:0.001
target:self
selector:#selector(timerFadeFired)
userInfo:nil
repeats:YES];
return self;
}
return nil;
}
- (BOOL) canBecomeKeyWindow
{
return YES;
}
- (void) display
{
[super display];
[self setAlphaValue:1.0];
}
- (void) setPrimaryText:(NSString *)text
{
NotificationView *view = self.contentView;
view.primaryLabel.stringValue = text;
}
- (void) setSecondaryText:(NSString *)text
{
NotificationView *view = self.contentView;
view.secondaryLabel.stringValue = text;
}
- (void) setIdentifierText:(NSString *)text
{
NotificationView *view = self.contentView;
view.identifierLabel.stringValue = text;
}
//===========================================================================================================================
// Private methods
//===========================================================================================================================
- (void) timerFadeFired
{
[self orderFront:NSApp];
if (self.fadeOut > 0)
{
self.fadeOut--;
}
else if (self.fadeOut == 0)
{
if (self.alphaValue > 0)
self.alphaValue -= 0.002;
else
self.fadeOut = -1;
}
}
#end
So I assume I'm doing something wrong connecting the labels to the IBOutlets, but I can't figure out what. I suppose I could create the view in code, but I was trying to be good and use the interface builder.
I'm in XCode 4.2.1.