I'm trying to display editable NSTextField on Mac in Cocos2d project. I run all my test code directly from AppDelegate to make test simple and eliminate all side effects. The code bellow shows red window with nice edit field. The trouble is that the field looks like without focus (text selection is gray) and is not editable (no cursor and no reaction to key strokes). I can change the text selection with mouse but that is all.
Any hint to what's wrong?
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
CCDirectorMac *director = (CCDirectorMac*) [CCDirector sharedDirector];
[glView_ setFrameSize:NSMakeSize(1024,768)];
[director setOpenGLView:glView_];
[director setResizeMode:kCCDirectorResize_AutoScale];
[glView_ setFrameSize:NSMakeSize(window_.frame.size.width,window_.frame.size.height-20)];
[window_ setContentAspectRatio:NSMakeSize(1024,768)];
[window_ setAcceptsMouseMovedEvents:NO];
[self addOverlayWindow];
//[director runWithScene:[MCGameScene scene]/*[HelloWorldLayer scene]*/];
}
- (void) addOverlayWindow;
{
NSRect windowRect = [[window_ contentView] frame] ;
NSWindow* uiWindow = [[NSWindow alloc] initWithContentRect:windowRect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered defer:YES];
[uiWindow setBackgroundColor: [NSColor redColor/*clearColor*/]];
[uiWindow setOpaque:NO];
NSView* uiView = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, windowRect.size.width, windowRect.size.height)] autorelease];
[uiView translateOriginToPoint:NSMakePoint(100, uiView.bounds.size.height/2)];
uiView.wantsLayer = YES;
[uiWindow setContentView:uiView];
NSTextField *textField;
textField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 800, 80)];
[textField setFont:[NSFont fontWithName:#"Helvetica Bold" size:60]];
[textField setStringValue:#"My XXXXXXXXX Label"];
[textField setBezeled:YES];
[textField setDrawsBackground:YES];
[textField setEditable:YES];
[textField setSelectable:YES];
[textField setEnabled:YES];
[uiView addSubview:textField];
// None of these combinations works...
// [textField becomeFirstResponder];
// [uiWindow setInitialFirstResponder:textField];
// [uiWindow makeFirstResponder:textField];
//[window_ makeFirstResponder:textField];
[window_ setInitialFirstResponder:textField];
// [uiView setInitialFirstResponder:textField];
// [uiView makeFirstResponder:textField];
[window_ addChildWindow:uiWindow ordered:NSWindowAbove];
}
Thanks in advance for your help,
--Josef
Related
I have an NSView NSButton and an NSTextField in this view's subviews
all of them are Layer Backed
I ma trying to animate this view changing frame.
- (void)animateTheView:(SPTabView *)view toFrame:(NSRect)endFrame
{
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context)
{
context.allowsImplicitAnimation = YES;
context.duration = ANIMATION_TIME;//is a define 0.6f
[view setFrame:endFrame];
} completionHandler:nil];
}
Edit In my view I am not using AutoLayout I am just overriding the setFrame:
- (void)setFrame:(NSRect)frame
{
[super setFrame:frame];
[_titleLabel setFrame:self.bounds]; //The NSTextField I am talking about
[_closeButton setFrame:NSMakeRect(5, 2, B_WIDTH, B_HEIGHT)];//This one works fine
[self removeTrackingRect:_tracking];
_tracking = [self addTrackingRect:[self bounds] owner:self userData:NULL assumeInside:NO];
}
EDIT 2 Posting the subViews Initialisation Code
[super setWantsLayer:YES];
[self setWantsLayer:YES];
[self setCanDrawSubviewsIntoLayer:YES];
[self drawRegular];
_closeButton = [[NSButton alloc]init];
[_closeButton setCanDrawSubviewsIntoLayer:YES];
[_closeButton setTitle:#"X"];
[_closeButton setTarget:self];
[_closeButton setAction:#selector(closeTab)];
[_closeButton setHidden:YES];
[_closeButton setWantsLayer:YES];
_titleLabel = [[SPLabel alloc]init]; //SPLabel is a silly subclass of NSTextField which just set it's properties like editable to as NO
[_titleLabel setText:#"Untitled.txt"];
[_titleLabel setTextColor:[NSColor blackColor]];
[_titleLabel setAlignment:NSCenterTextAlignment];
[_titleLabel setWantsLayer:YES];
[_titleLabel setTag:6];
[self addSubview:_titleLabel];
[self addSubview:_closeButton];
My view and it's button animating FINE! but the textField doesn't animate at all - it just jumps to the EndFrame...
Any Ideas some1 ?
All I am trying to do is add a new view to the content view of my NSWindow instance. When I do the following I do not see the new view (which should be black and take up the entire window). What am I doing wrong?
(done in response to a button click)
NSRect frameRect = [self.window frame];
frameRect.origin = NSZeroPoint;
NSView *view = [[NSView alloc] initWithFrame:frameRect];
view.wantsLayer = YES;
view.layer.backgroundColor = [NSColor blackColor].CGColor;
[self.window.contentView addSubview:view];
I've set up a simple project with a push button inside a ViewController and got a warning for accessing self.window. When using self.view.windowthe warning went away and your provided code works as expected.
Updated code
NSRect frameRect = [self.view.window frame];
frameRect.origin = NSZeroPoint;
NSView *view = [[NSView alloc] initWithFrame:frameRect];
view.wantsLayer = YES;
view.layer.backgroundColor = [NSColor blackColor].CGColor;
[self.view.window.contentView addSubview:view];
Update
Assuming that you're using an instance of WindowController where you're adding a button programmatically, your code works as expected.
#implementation WindowController
- (void)windowDidLoad
{
[super windowDidLoad];
CGRect buttonRect = CGRectMake(self.window.frame.size.width / 2 - 50,
self.window.frame.size.height / 2,
100,
50);
NSButton *button = [[NSButton alloc] initWithFrame:NSRectFromCGRect(buttonRect)];
[button setTitle: #"Click me!"];
[button setTarget:self];
[button setAction:#selector(buttonPressed)];
[self.window.contentView addSubview:button];
}
- (void)buttonPressed
{
NSRect frameRect = [self.window frame];
frameRect.origin = NSZeroPoint;
NSView *view = [[NSView alloc] initWithFrame:frameRect];
view.wantsLayer = YES;
view.layer.backgroundColor = [NSColor blackColor].CGColor;
[self.window.contentView addSubview:view];
}
An instance of NSViewController ain't got a property of window - only NSWindowController has one.
I wish to create a window without a nib file which consists entirely of an NSTextView.
It should act as a popup but still be modeless.
So far I have two properties:
#property (strong,nonatomic) NSWindow *consoleWindow;
#property (strong,nonatomic) NSTextView* textView;
Here is what my implementation looks like:
-(void)doubleAction:(NSOutlineView*)sender
{
if(self.currentLogEntry == nil)
{
return;
}
self.consoleWindow = nil;
self.textView = nil;
NSRect windowRect = NSMakeRect(10.0f, 10.0f, 500.0f, 400.0f);
self.consoleWindow = [[NSWindow alloc] initWithContentRect:windowRect
styleMask:( NSResizableWindowMask | NSClosableWindowMask | NSTitledWindowMask)
backing:NSBackingStoreBuffered defer:NO];
self.textView = [[NSTextView alloc] initWithFrame:[[self.consoleWindow contentView] frame]];
[self.textView setString:self.currentLogEntry.value];
[self.consoleWindow setContentView:self.textView];
[self.consoleWindow makeKeyAndOrderFront:nil];
[self.consoleWindow makeFirstResponder:self.textView];
NSLog(#"Double clicked");
}
Things have been wired up so I have a list of entries, whenever I double click on an entry the selected entry is loaded into self.currentLogEntry and this method is then fired. It works but if I close the window and try to open another entry I get Thread 1:EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
I think it has something to do with the window not being released properly but I have tried a few things like setting the properties to nil whenever the program enters the doubleAction (as you can see in the code) but that doesn't help.
Any help solving this problem is greatly appreciated.
The soulution was to: [self.consoleWindow setReleasedWhenClosed:NO];
Here is how the full code ended out being (only relevant parts):
.h:
#property (strong,nonatomic) NSWindow *consoleWindow;
#property (strong,nonatomic) NSTextView* textView;
#property (strong,nonatomic) NSScrollView* scrollView;
.m:
-(void)doubleAction:(NSOutlineView*)sender
{
if(self.currentLogEntry == nil)
{
return;
}
self.consoleWindow = nil;
self.textView = nil;
self.scrollView = nil;
NSRect windowRect = NSMakeRect(10.0f, 10.0f, 500.0f, 400.0f);
self.consoleWindow = [[NSWindow alloc] initWithContentRect:windowRect
styleMask:( NSResizableWindowMask | NSClosableWindowMask | NSTitledWindowMask)
backing:NSBackingStoreBuffered defer:NO];
[self.consoleWindow setReleasedWhenClosed:NO];
self.scrollView = [[NSScrollView alloc] initWithFrame:[[self.consoleWindow contentView] frame]];
[self.scrollView setBorderType:NSNoBorder];
[self.scrollView setHasVerticalScroller:YES];
[self.scrollView setHasHorizontalScroller:NO];
[self.scrollView setAutoresizingMask:NSViewWidthSizable |
NSViewHeightSizable];
NSSize contentSize = [self.scrollView contentSize];
self.textView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0,
contentSize.width, contentSize.height)];
[self.textView setMinSize:NSMakeSize(0.0, contentSize.height)];
[self.textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[self.textView setVerticallyResizable:YES];
[self.textView setHorizontallyResizable:NO];
[self.textView setAutoresizingMask:NSViewWidthSizable];
[[self.textView textContainer]
setContainerSize:NSMakeSize(contentSize.width, FLT_MAX)];
[[self.textView textContainer] setWidthTracksTextView:YES];
[self.textView setString:self.currentLogEntry.value];
[self.scrollView setDocumentView:self.textView];
[self.consoleWindow setContentView:self.scrollView];
[self.consoleWindow makeKeyAndOrderFront:nil];
[self.consoleWindow makeFirstResponder:self.textView];
NSLog(#"Double clicked");
}
I have two UITextViews, self.instructions and self.textView, that are supposed to alternate depending on what the user selects.
I create a self.textView like so:
-(void)createSpaceToWrite
{
[self.instructions removeFromSuperview];
[self.bar removeFromSuperview];
[self createNavigationBar:#"Compose" selector:#"displayScreen" withDone:NO]; //This adds a UINavigationBar to the view.
if (!self.textView)
{
self.textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 60, 280, 150)];
}
self.textView.backgroundColor = [UIColor whiteColor];
self.textView.font = [UIFont fontWithName:#"Helvetica Neue" size:14];
self.textView.text = #"";
[self.view addSubview:self.textView];
self.textView.delegate = self;
}
Then I create self.instructions like so:
-(void)haikuInstructions
{
[self.textView removeFromSuperview];
[self.bar removeFromSuperview];
[self createNavigationBar:#"Compose" selector:#"displayScreen" withDone:NO];
if (!self.instructions)
{
self.instructions = [[UITextView alloc] initWithFrame:CGRectMake(10, 125, [[UIScreen mainScreen] bounds].size.width - 10, [[UIScreen mainScreen] bounds].size.height)];
}
self.instructions.backgroundColor=[UIColor clearColor];
self.instructions.text = #"Text of instructions";
self.instructions.editable=NO;
[self.view addSubview:self.instructions];
[self resignFirstResponder];
}
The user starts with self.instructions displayed against the background image. Fine.
The user switches. The instruction text disappears, to be replaced by the editable self.textView, a white box. Fine.
The user switches back. The instruction text appears--but the white box is still there, even thought I've removed it from the superview. And not only that, it's still editable and still brings up the keyboard when the user goes to edit it!
What am I doing wrong?
EDIT: Well, I basically scrapped all the code and started the class over from scratch, trying to be cleaner about everything, and I'm no longer having this problem, so it must have been something in some other method that was affecting it. Lesson: haphazard coding is bad!
Why do you need to remove your text views interchangeably? Wouldn't it be better to just "hide" them interchangeably by setting the setHidden property like for example:
[self.textView setHidden: YES];
and additionally try the following also:
[self.textView resignFirstResponder];
[self.textView setEditable: NO];
[self.textView setBackgroundColor: [UIColor clearColor]];
[self.textView setAlpha: 0.0];
My code:
- (void)viewDidLoad {
[super viewDidLoad];
CGRect rectFake = CGRectZero;
UITextField *fakeField = [[UITextField alloc] initWithFrame:rectFake];
[self.view addSubview:fakeField];
UIView *av = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 39.0)];
av.backgroundColor = [UIColor darkGrayColor];
CGRect rect = CGRectMake(200.0, 4.0, 400.0, 31.0);
UITextField *textField = [[UITextField alloc] initWithFrame:rect];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.font = [UIFont systemFontOfSize:24.0];
textField.delegate = self;
[av addSubview:textField];
fakeField.inputAccessoryView = av;
[fakeField becomeFirstResponder];
}
I tried to add
[textField becomeFirstResponder]
at the end, but it does no work.
Another problem that delegate method to hide keyboard when ENTER is pressed does not work also.
- (BOOL) textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
I was facing the same challenge. Your (and my initial) approach probably don't work because the text field in the inputAccessoryView refuses to become first responder as the UITextField is not located on your screen initially.
My solution: check when the keyboard (and with that the accessory view) appear!
Step 1) Listen for the notification (make sure this code is executed before you want to receive the notification).
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(changeFirstResponder)
name:UIKeyboardDidShowNotification
object:nil];
Step 2) When the keyboard has appeared, you can set the textfield in your inputAccessoryView to become first responder:
-(void)changeFirstResponder
{
[textField becomeFirstResponder]; // will return YES;
}