NSTextField Tab Order.

  • Hello, All,

    I have a window with a number of NSTextFields in two columns. The natural flow of information would be to fill in one column then the other but the tab order goes left to right then down.

    I've tried hooking up the nextKeyView in IB but that doesn't help. I've also used [window setAutorecalculatesKeyViewLoop:NO]; in windowDidLoad (and in IB it's un-ticked) which doesn't help either - mind you despite window being hooked up in IB window == NULL but the notifications below are being called and they don't work either.

    Now I'm trying a notification system

    For each NSTextField I use this in windowDidLoad:

      [[NSNotificationCenter defaultCenter] addObserver:self
                                                selector:@selector (controlTextDidEndEditing:)
                                                    name:NSControlTextDidEndEditingNotification
                                                  object:titleField];

    Then:

    - (void)controlTextDidEndEditing:(NSNotification *)notification
    {
    NSTextField *f = [notification object];

      if (f == titleField)
          {
          [titleField resignFirstResponder];
          [window setInitialFirstResponder:forenameField];
          }
      else if (f == forenameField)
          [forenameField resignFirstResponder];
          [window setInitialFirstResponder:surnameField];
          ...

    but this isn't working either.

    I'm sure there must be an easier way to do this, would anyone know what it is?

    Regards, Rob.
  • On Jun 13, 2012, at 3:40 AM, Robert Tillyard wrote:

    > mind you despite window being hooked up in IB window == NULL

    You need to figure this out first.  It's indicative of a deeper problem.

    Are you referring to the window property of a custom subclass of NSWindowController?  Is this window controller being instantiated in code?  If so, what initializer is called?  How is that initializer implemented?  In particular, I'm looking to make sure that -initWithWindowNibName: was called, or, if -initWithWindowNibName:owner: was called instead that the window controller passed itself as the owner (making use of that method redundant).

    In the NIB, did you set the class of File's Owner to be your window controller class?  Was it File's Owner's window outlet that you hooked up?  A common mistake is to actually instantiate the window controller in the NIB and therefore have two window controllers.  That won't work right, obviously.

    At what point did you attempt to use the window outlet?  If it was before -awakeFromNib or -windowDidLoad, it would be too early.  A common mistake is to attempt to reference the window during the initializer.

    > I've tried hooking up the nextKeyView in IB but that doesn't help. I've also used [window setAutorecalculatesKeyViewLoop:NO]; in windowDidLoad (and in IB it's un-ticked) which doesn't help either

    Did you set the initialFirstResponder outlet of the window to point to the first key view in your loop?  According to the docs for -[NSWindow recalculateKeyViewLoop], it is called "when [the window] is first loaded, ... automatically if your window does not have a key view loop already established".  I suspect that means if initialFirstResponder is not set.  So, I suspect that failing to set that means that the method will blow away your configuration of nextKeyView connections.

    Regards,
    Ken
  • Hello, Ken,

    Thank you for your reply.

    On 13 Jun 2012, at 10:47, Ken Thomases wrote:

    > On Jun 13, 2012, at 3:40 AM, Robert Tillyard wrote:
    >
    >> mind you despite window being hooked up in IB window == NULL
    >
    > You need to figure this out first.  It's indicative of a deeper problem.

    I've checked again and it's still NULL.

    > Are you referring to the window property of a custom subclass of NSWindowController?  Is this window controller being instantiated in code?  If so, what initializer is called?  How is that initializer implemented?  In particular, I'm looking to make sure that -initWithWindowNibName: was called, or, if -initWithWindowNibName:owner: was called instead that the window controller passed itself as the owner (making use of that method redundant).

    Window is created from a XIB using:

    - (id)initWithManagedObjectContext:(NSManagedObjectContext *)inMoc
    {
      if ((self = [super initWithWindowNibName:@"RunnersWindow" owner:self]))
          [self setManagedObjectContext:inMoc];

      return (self);
    }

    - (void)windowDidLoad
    {
      [window setAutorecalculatesKeyViewLoop:NO];
      NSLog (@"windowDidLoad: Window = %@\n", window);
    }

    > In the NIB, did you set the class of File's Owner to be your window controller class?  Was it File's Owner's window outlet that you hooked up?  A common mistake is to actually instantiate the window controller in the NIB and therefore have two window controllers.  That won't work right, obviously.

    In the XIB Files Owner is set to my WindowController sub-class.

    The Files Owner's window outlet says it's linked to window but I have in the past had problem in a different project where I had two awakeFromNibs called, I don't know how that happened but it seems that something I did in that project caused two instances of my window controller to be created.

    How would I know if I've instantiated the window controller in my NIB? would I see two windowDidLoad messages?

    > At what point did you attempt to use the window outlet?  If it was before -awakeFromNib or -windowDidLoad, it would be too early.  A common mistake is to attempt to reference the window during the initializer.
    >

    I use the window outlet in windowDidLoad and in the method called by the NSControlTextDidEndEditingNotification notifications.

    >
    >> I've tried hooking up the nextKeyView in IB but that doesn't help. I've also used [window setAutorecalculatesKeyViewLoop:NO]; in windowDidLoad (and in IB it's un-ticked) which doesn't help either
    >
    > Did you set the initialFirstResponder outlet of the window to point to the first key view in your loop?  According to the docs for -[NSWindow recalculateKeyViewLoop], it is called "when [the window] is first loaded, ... automatically if your window does not have a key view loop already established".  I suspect that means if initialFirstResponder is not set.  So, I suspect that failing to set that means that the method will blow away your configuration of nextKeyView connections.

    Okay, here I can see I screwed that up. I had no initialFirstResponder, now I've set it the tab order works perfectly.

    I'd still like to fix my window == NULL problem as I would like to make the enter key move to the next field and skip fields if some earlier information means that future fields are not required.

    > Regards,
    > Ken

    Thanks, again for taking the time to help.

    Regards, Rob.
  • On Jun 13, 2012, at 2:15 PM, Robert Tillyard wrote:

    > I'd still like to fix my window == NULL problem as I would like to make the enter key move to the next field and skip fields if some earlier information means that future fields are not required.

    Is there any chance you could be shadowing a built-in window property with your window property or iVar? I have had a problem similar to yours because of doing that.
  • On Jun 13, 2012, at 14:15 , Robert Tillyard wrote:

    > Window is created from a XIB using:
    >
    > - (id)initWithManagedObjectContext:(NSManagedObjectContext *)inMoc
    > {
    > if ((self = [super initWithWindowNibName:@"RunnersWindow" owner:self]))
    > [self setManagedObjectContext:inMoc];
    >
    > return (self);
    > }
    >
    > - (void)windowDidLoad
    > {
    > [window setAutorecalculatesKeyViewLoop:NO];
    > NSLog (@"windowDidLoad: Window = %@\n", window);
    > }

    > I'd still like to fix my window == NULL problem

    You're referring to a "window" instance variable that NSWindowController does not define, so I assume you defined it yourself. If so, that's a mistake. You're supposed to refer to the "window" property -- self.window.

    In IB, when you connect what looks alike a "window" outlet, you're actually connecting the NSWindowController's private "_window" ivar (or perhaps, these days, it's connecting the "window" property, I don't know). That means your separately-defined "window" ivar won't get connected and will always contain nil. You should get rid of this ivar from your subclass.

    The other difficulty you're running into is that by design the window is not created immediately when you create a window controller. (You say of your code, above, that it creates a window from a XIB. It doesn't. It only creates a window controller.)

    Instead, the window is created the first time something refers to the window controller's "window" property (e.g. 'self.window' if it's referred to from within the window controller itself). At that point, the NIB is instantiated, the window created, and 'windowDidLoad' is invoked.
  • Hi,

    On Jun 13, 2012, at 4:15 PM, Robert Tillyard wrote:

    > Thank you for your reply.

    You're welcome.

    > Window is created from a XIB using:
    >
    > - (id)initWithManagedObjectContext:(NSManagedObjectContext *)inMoc
    > {
    > if ((self = [super initWithWindowNibName:@"RunnersWindow" owner:self]))
    > [self setManagedObjectContext:inMoc];
    >
    > return (self);
    > }
    >
    > - (void)windowDidLoad
    > {
    > [window setAutorecalculatesKeyViewLoop:NO];
    > NSLog (@"windowDidLoad: Window = %@\n", window);
    > }

    If you're referring to it plain that way, then it must be an instance variable of your own, as Dennis suggested.  Assuming this is a subclass of NSWindowController as it seems to be, then you should be using the window property that it defines.  So, you'd do [self window] or self.window, not just window.  Remove any extra window instance variable or property declaration from your class.

    > How would I know if I've instantiated the window controller in my NIB? would I see two windowDidLoad messages?

    You would see an actual object, not the File's Owner placeholder, listed among the top-level objects of the NIB.  It would usually be a blue cube "object" whose class you had set to be your window controller class.

    Regards,
    Ken
  • On 13 Jun 2012, at 22:50, Quincey Morris wrote:

    > On Jun 13, 2012, at 14:15 , Robert Tillyard wrote:
    >
    >> Window is created from a XIB using:
    >>
    >> - (id)initWithManagedObjectContext:(NSManagedObjectContext *)inMoc
    >> {
    >> if ((self = [super initWithWindowNibName:@"RunnersWindow" owner:self]))
    >> [self setManagedObjectContext:inMoc];
    >>
    >> return (self);
    >> }
    >>
    >> - (void)windowDidLoad
    >> {
    >> [window setAutorecalculatesKeyViewLoop:NO];
    >> NSLog (@"windowDidLoad: Window = %@\n", window);
    >> }
    >
    >> I'd still like to fix my window == NULL problem
    >
    >
    > You're referring to a "window" instance variable that NSWindowController does not define, so I assume you defined it yourself. If so, that's a mistake. You're supposed to refer to the "window" property -- self.window.
    >
    > In IB, when you connect what looks alike a "window" outlet, you're actually connecting the NSWindowController's private "_window" ivar (or perhaps, these days, it's connecting the "window" property, I don't know). That means your separately-defined "window" ivar won't get connected and will always contain nil. You should get rid of this ivar from your subclass.
    >
    > The other difficulty you're running into is that by design the window is not created immediately when you create a window controller. (You say of your code, above, that it creates a window from a XIB. It doesn't. It only creates a window controller.)
    >
    > Instead, the window is created the first time something refers to the window controller's "window" property (e.g. 'self.window' if it's referred to from within the window controller itself). At that point, the NIB is instantiated, the window created, and 'windowDidLoad' is invoked.

    Thanks to Ken, Dennis and Quincey.

    I had an instance variable IBOutlet NSWindow *window in the header file that was shadowing the property.

    Everything is working now.

    Thanks everyone for taking the time to help.

    Regards, Rob.
  • On Jun 13, 2012, at 4:50 PM, Quincey Morris wrote:

    > The other difficulty you're running into is that by design the window is not created immediately when you create a window controller. (You say of your code, above, that it creates a window from a XIB. It doesn't. It only creates a window controller.)
    >
    > Instead, the window is created the first time something refers to the window controller's "window" property (e.g. 'self.window' if it's referred to from within the window controller itself). At that point, the NIB is instantiated, the window created, and 'windowDidLoad' is invoked.

    Correct with the caveat that there's at least one method, -showWindow:, which causes NSWindowController to load the window without you having to explicitly use the window property.

    Regards,
    Ken
previous month june 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  
Go to today