Modal Window for NSTextField

  • Hello everyone!

    I would like to ask your help with a specific problem I have.

    I need to implement the following thing:
    There is a control displaying numeric value. When you Double-Click on a control small white window appears where you can enter the value, and when you press enter the value will be updated.
    You can see this screenshot (Ignore the fact it is from Windows 7):

    http://i31.fastpic.ru/big/2012/0102/5e/3d39b295e3dc2642ff1d0f240da0c95e.png

    Here is the code. I do it not within the main view but from the side function. The superView is the main view.

    NSRect textRect    = NSMakeRect(in_location.m_x, in_location.m_y, in_size.m_x, in_size.m_y);
    NSTextField* textField = [[NSTextField alloc] initWithFrame:textRect];

    // Configure the text field
    [textField setEditable:YES];
    [textField setSelectable:YES];
    [textField setWantsLayer:YES];
    [textField setImportsGraphics:NO];
    [textField setBordered:NO];
    [textField setBezeled:NO];
    [textField setBackgroundColor:[NSColor whiteColor]];
    [textField setDrawsBackground:YES];
    [textField setTextColor:[NSColor blackColor]];
    [textField setAllowsEditingTextAttributes:NO];
    [textField setAutoresizingMask:(NSUInteger)(NSViewWidthSizable + NSViewHeightSizable)];

    // Embed the text field in our plug-in view.
    [superView addSubview:textField];
    [superView setAutoresizesSubviews:YES];

    // Make the text field "in focus", and start an editing session on it
    [textField becomeFirstResponder];

    Now I tried 2 approaches:

    1)

    *out_dismissedKey = [NSApp runModalForWindow:[textField window]];
    [textField removeFromSuperview];
    [textField release];

    This one works. The text window gets all the events and I can get what I want. However, the windows order get screwed, meaning if there are couple of windows open in the same application the superView gets beyond other windows and I can not get it on front again.

    So I tried the second approach - sheets:

    2)

    [textField beginSheetModalForWindow:[superView window] modalDelegate:superView didEndSelector:0 contextInfo:0];
    [textField removeFromSuperview];
    [textField release];

    Now the problem here is that I am getting stuck in this function. The window is opened but neither Enter nor Escape do not close it. So the caller function can not continue, meaning I can not reach
    [textField removeFromSuperview].

    Can someone help me either with first or the second issue?
    I understand that the explanation may be insufficient, I am ready to give more and the screenshots if anyone wishes.

    Thanks!

    [cid:<image001.jpg...>]

    Dany Golubitsky
    Software Engineer

    Waves Audio Ltd
    Tel:  +972 3 608 4157
    Fax: +972 3 608 4056

    www.waves.com<http://www.waves.com/
  • On Jan 2, 2012, at 6:02 AM, Dany Golubitsky wrote:

    > I need to implement the following thing:
    > There is a control displaying numeric value. When you Double-Click on a control small white window appears where you can enter the value, and when you press enter the value will be updated.
    > You can see this screenshot (Ignore the fact it is from Windows 7):
    >
    > http://i31.fastpic.ru/big/2012/0102/5e/3d39b295e3dc2642ff1d0f240da0c95e.png

    What you are trying to implement sounds very similar to the standard field editor used in Cocoa (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Text
    Editing/Tasks/FieldEditor.html
    ).

    If you aren't familiar with it, I'd advise taking some time to investigate it and see if you can adapt it to your needs. Even if not, the description of how it works (integration with responder chain, delegate methods) should prove useful. I would recommend it over the approach of trying to force application or window modal operation.

    > Here is the code. I do it not within the main view but from the side function. The superView is the main view.
    >
    > NSRect textRect    = NSMakeRect(in_location.m_x, in_location.m_y, in_size.m_x, in_size.m_y);
    > NSTextField* textField = [[NSTextField alloc] initWithFrame:textRect];
    >
    > // Configure the text field
    > [textField setEditable:YES];
    > [textField setSelectable:YES];
    > [textField setWantsLayer:YES];
    > [textField setImportsGraphics:NO];
    > [textField setBordered:NO];
    > [textField setBezeled:NO];
    > [textField setBackgroundColor:[NSColor whiteColor]];
    > [textField setDrawsBackground:YES];
    > [textField setTextColor:[NSColor blackColor]];
    > [textField setAllowsEditingTextAttributes:NO];
    > [textField setAutoresizingMask:(NSUInteger)(NSViewWidthSizable + NSViewHeightSizable)];
    >
    > // Embed the text field in our plug-in view.
    > [superView addSubview:textField];
    > [superView setAutoresizesSubviews:YES];
    >
    > // Make the text field "in focus", and start an editing session on it
    > [textField becomeFirstResponder];
    >
    > Now I tried 2 approaches:
    >
    > 1)
    >
    > *out_dismissedKey = [NSApp runModalForWindow:[textField window]];
    > [textField removeFromSuperview];
    > [textField release];
    >
    > This one works. The text window gets all the events and I can get what I want. However, the windows order get screwed, meaning if there are couple of windows open in the same application the superView gets beyond other windows and I can not get it on front again.

    Given the code, it looks like you're trying to force the window with the text field into an application modal "mode". Don't do this.

    > So I tried the second approach - sheets:
    >
    > 2)
    >
    > [textField beginSheetModalForWindow:[superView window] modalDelegate:superView didEndSelector:0 contextInfo:0];
    > [textField removeFromSuperview];
    > [textField release];
    >
    > Now the problem here is that I am getting stuck in this function. The window is opened but neither Enter nor Escape do not close it. So the caller function can not continue, meaning I can not reach
    > [textField removeFromSuperview].

    So textField is an NSSavePanel or NSAlert? Those seem to be the only objects (other than more obscure objects like ABIdentityPicker) with beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo: methods.

    I'll assume you meant  - [NSApplication beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo:]. It requires an endSheet call (delegate method? notification?) to exit. In any case, I would not recommend this approach either.
  • Thank you!

    As for field editor - can it appear and disappear during runtime? Indeed, I do not familiar with this approach.

    About beginSheetModalForWindow - indeed, I tried to do the following either:
    [textField beginSheet:[textField window] ModalForWindow:[superView window] modalDelegate:superView didEndSelector:0 contextInfo:0];

    and yes, I implemented endSheet. I tried to call endSheet from mouseDown event. I saw this function being called, however still, the white window was not closed and I was stuck in beginSheet (The code after it was unreachable).

    Can you suggest why?

    -----Original Message-----
    From: Michael Babin [mailto:<mbabin...>]
    Sent: Monday, January 02, 2012 16:10
    To: Dany Golubitsky
    Cc: <cocoa-dev...>
    Subject: Re: Modal Window for NSTextField

    On Jan 2, 2012, at 6:02 AM, Dany Golubitsky wrote:

    > I need to implement the following thing:
    > There is a control displaying numeric value. When you Double-Click on a control small white window appears where you can enter the value, and when you press enter the value will be updated.
    > You can see this screenshot (Ignore the fact it is from Windows 7):
    >
    > http://i31.fastpic.ru/big/2012/0102/5e/3d39b295e3dc2642ff1d0f240da0c95
    > e.png

    What you are trying to implement sounds very similar to the standard field editor used in Cocoa (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Text
    Editing/Tasks/FieldEditor.html
    ).

    If you aren't familiar with it, I'd advise taking some time to investigate it and see if you can adapt it to your needs. Even if not, the description of how it works (integration with responder chain, delegate methods) should prove useful. I would recommend it over the approach of trying to force application or window modal operation.

    > Here is the code. I do it not within the main view but from the side function. The superView is the main view.
    >
    > NSRect textRect    = NSMakeRect(in_location.m_x, in_location.m_y, in_size.m_x, in_size.m_y);
    > NSTextField* textField = [[NSTextField alloc] initWithFrame:textRect];
    >
    > // Configure the text field
    > [textField setEditable:YES];
    > [textField setSelectable:YES];
    > [textField setWantsLayer:YES];
    > [textField setImportsGraphics:NO];
    > [textField setBordered:NO];
    > [textField setBezeled:NO];
    > [textField setBackgroundColor:[NSColor whiteColor]]; [textField
    > setDrawsBackground:YES]; [textField setTextColor:[NSColor
    > blackColor]]; [textField setAllowsEditingTextAttributes:NO];
    > [textField setAutoresizingMask:(NSUInteger)(NSViewWidthSizable +
    > NSViewHeightSizable)];
    >
    > // Embed the text field in our plug-in view.
    > [superView addSubview:textField];
    > [superView setAutoresizesSubviews:YES];
    >
    > // Make the text field "in focus", and start an editing session on it
    > [textField becomeFirstResponder];
    >
    > Now I tried 2 approaches:
    >
    > 1)
    >
    > *out_dismissedKey = [NSApp runModalForWindow:[textField window]];
    > [textField removeFromSuperview]; [textField release];
    >
    > This one works. The text window gets all the events and I can get what I want. However, the windows order get screwed, meaning if there are couple of windows open in the same application the superView gets beyond other windows and I can not get it on front again.

    Given the code, it looks like you're trying to force the window with the text field into an application modal "mode". Don't do this.

    > So I tried the second approach - sheets:
    >
    > 2)
    >
    > [textField beginSheetModalForWindow:[superView window]
    > modalDelegate:superView didEndSelector:0 contextInfo:0]; [textField
    > removeFromSuperview]; [textField release];
    >
    > Now the problem here is that I am getting stuck in this function. The
    > window is opened but neither Enter nor Escape do not close it. So the caller function can not continue, meaning I can not reach [textField removeFromSuperview].

    So textField is an NSSavePanel or NSAlert? Those seem to be the only objects (other than more obscure objects like ABIdentityPicker) with beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo: methods.

    I'll assume you meant  - [NSApplication beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo:]. It requires an endSheet call (delegate method? notification?) to exit. In any case, I would not recommend this approach either.
  • On Jan 2, 2012, at 9:22 AM, Dany Golubitsky wrote:

    > Thank you!
    >
    > As for field editor - can it appear and disappear during runtime? Indeed, I do not familiar with this approach.

    "The field editor is a single NSTextView object that is shared among all the controls in a single window, including buttons, table views, and text fields. This text view object provides text entry and editing services for the currently active control. When the user clicks in a text field, for example, the field editor begins handling keystroke events and text display for that field."

    So, yes.

    > About beginSheetModalForWindow - indeed, I tried to do the following either:
    > [textField beginSheet:[textField window] ModalForWindow:[superView window] modalDelegate:superView didEndSelector:0 contextInfo:0];

    Again assuming that you mean  - [NSApplication beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo:], you would not send that message to textField (which is not an NSApplication object, unless your approach/naming has changed much more radically than described).

    Given that textField is a subview of superView, you're attempting to use a window as a sheet for itself. I doubt that approach would yield useful results.

    > and yes, I implemented endSheet. I tried to call endSheet from mouseDown event. I saw this function being called, however still, the white window was not closed and I was stuck in beginSheet (The code after it was unreachable).
    >
    > Can you suggest why?

    - [NSApplication endSheet:] and -[NSApplication endSheet: returnCode:] do work to end a modal session using a sheet, in my experience, provided you supply the appropriate arguments. Your problem could also be due to trying to use a window as a sheet for itself, as mentioned previously.
  • On Jan 2, 2012, at 4:02 AM, Dany Golubitsky wrote:

    > // Make the text field "in focus", and start an editing session on it
    > [textField becomeFirstResponder];

    -becomeFirstResponder is a notification method for when the responder becomes first responder; it doesn't *make* it first responder. For that you want [window makeFirstResponder:].

    > Now I tried 2 approaches:

    Both are wacky as Michael explained.

    You do not need the window to be modal at all. The solution is really simple. Just start editing the text field, and when the editing is done (controlTextDidEndEditing: notification), you just remove the text field.

    --
    Seth Willits
  • Hello again.

    I am sorry, I am new to Cocoa and some things that looks completely obvious to you are completely unknown to me.
    (controlTextDidEndEditing: notification) - What is this function, where should it be implemented, who should call it?
    How need I start the TextField?

    For my code I need to call opening function, wait for it to open, get text from user and return. Meaning:

    {
    Block 1
    }
    Calling for TextField and waiting for return value.
    {
    Block 2
    }

    Getting return value in some other place is not an option.

    Is there any example of this?

    Thanks!

    -----Original Message-----
    From: cocoa-dev-bounces+danyg=<waves.com...> [mailto:cocoa-dev-bounces+danyg=<waves.com...>] On Behalf Of Seth Willits
    Sent: Monday, January 02, 2012 20:28
    To: cocoa-dev cocoa-dev
    Subject: Re: Modal Window for NSTextField

    On Jan 2, 2012, at 4:02 AM, Dany Golubitsky wrote:

    > // Make the text field "in focus", and start an editing session on it
    > [textField becomeFirstResponder];

    -becomeFirstResponder is a notification method for when the responder becomes first responder; it doesn't *make* it first responder. For that you want [window makeFirstResponder:].

    > Now I tried 2 approaches:

    Both are wacky as Michael explained.

    You do not need the window to be modal at all. The solution is really simple. Just start editing the text field, and when the editing is done (controlTextDidEndEditing: notification), you just remove the text field.

    --
    Seth Willits
  • On 3 Jan 2012, at 3:29 AM, Dany Golubitsky wrote:

    > I am sorry, I am new to Cocoa and some things that looks completely obvious to you are completely unknown to me.
    > (controlTextDidEndEditing: notification) - What is this function, where should it be implemented, who should call it?

    It is a delegate method of NSControl. (Read up on the "delegate" design pattern for the concept.) You must make some object a delegate of each field you want to respond to; the object can then respond to the current value of the field. Use the firstResponder method of the enclosing window to get a pointer to the field. Searching the documentation will tell you more. (Perhaps you've done that, and don't want to believe what you're seeing.)

    > How need I start the TextField?

    Send it to the window as the parameter for the window's -makeFirstResponder: method.

    > For my code I need to call opening function, wait for it to open, get text from user and return. Meaning:
    >
    > {
    > Block 1
    > }
    > Calling for TextField and waiting for return value.
    > {
    > Block 2
    > }
    >
    > Getting return value in some other place is not an option.

    Running a text field modally is not a favored option. Few developers do it, because it's easier to defer processing till their did-end-editing method is called. It might be possible to lash something together with a borderless window, but this is a framework: _It_ calls _you_. If you want to program for the Macintosh, you really have to be able to design for asynchrony. Fighting the framework is a losing proposition.

    — F
  • On 03/01/2012, at 8:29 PM, Dany Golubitsky wrote:

    > Calling for TextField and waiting for return value.

    > Getting return value in some other place is not an option.

    It simply doesn't work that way. In fact there's almost no code in Cocoa that does work that way, with the possible exception of NSAlert.

    Read the documentation about the "field editor" and how it works, and how it is used by controls such as NSTextField. It's not especially complicated, but it's not as simplistic as you are assuming. Blindly throwing your own misconceptions about how the framework works at the problem will certainly lead to disappointment and frustration.

    --Graham
previous month january 2012 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Go to today