Set focus on NSView in an NSMenuItem

  • Hi everyone,

    I got another question regarding the new setView method in Leopard.
    Let's assume I set the view for an NSMenuItem to myView. myView
    contains an NSTextField. Now when I open the NSMenu I want to set the
    focus on this textfield, so the user can directly enter some text
    without having to click on the control first (like it works in the
    spotlight menu). How can I achieve that? I know how to call
    keyOrderAndFront and setFirstRespinder for NSWindows but how can I do
    this with an NSMenu. Setting the firstresponder for myView to the
    NSTextField does not help unfortunately.

    Best,

    Hendrik
  • On Jan 4, 2008, at 6:20 AM, Hendrik Holtmann wrote:

    > Hi everyone,
    >
    > I got another question regarding the new setView method in Leopard.
    > Let's assume I set the view for an NSMenuItem to myView. myView
    > contains an NSTextField. Now when I open the NSMenu I want to set
    > the focus on this textfield, so the user can directly enter some
    > text without having to click on the control first (like it works in
    > the spotlight menu). How can I achieve that? I know how to call
    > keyOrderAndFront and setFirstRespinder for NSWindows but how can I
    > do this with an NSMenu. Setting the firstresponder for myView to
    > the NSTextField does not help unfortunately.

    Probably the easiest approach would be to override
    viewDidMoveToWindow on the view that will be in the menu, and from
    within it call [[self window] makeFirstResponder:self];.
    makeFirstResponder is one of a very few methods that is safe to call
    on the menu window.

    -Peter
  • Hi Peter!
    Hi Hendrik!

    I have almost the same setup as Hendrik: I use a NSSearchField in a
    menu. When the menu is opened I want the focus to go to the search
    field.

    At first sight, the solution suggested by Peter appears to work fine.
    But something goes wrong. My search field misbehaves when I do this.

    To be exact, the window's text editor does not respect the properties
    of my search field. E.g. if I hit return while editing, I get a
    newline in my search field. I however expect the search field's action
    to be called.

    So I figured, I could delay setting the focus using
    performSelector:afterDelay: or using a NSTimer. I wouldn't know if
    this could alleviate the above described problem. The thing is: in
    both cases my selector only gets called after the menu is dismissed.

    Hendrik, did you get this to work as expected?
    Peter, could it be that the text editor is called upon too early?

    Best,
    Pierre

    On 4 Jan 2008, at 21:30, Peter Ammon wrote:

    >
    > On Jan 4, 2008, at 6:20 AM, Hendrik Holtmann wrote:
    >
    >> Hi everyone,
    >>
    >> I got another question regarding the new setView method in Leopard.
    >> Let's assume I set the view for an NSMenuItem to myView. myView
    >> contains an NSTextField. Now when I open the NSMenu I want to set
    >> the focus on this textfield, so the user can directly enter some
    >> text without having to click on the control first (like it works in
    >> the spotlight menu). How can I achieve that? I know how to call
    >> keyOrderAndFront and setFirstRespinder for NSWindows but how can I
    >> do this with an NSMenu. Setting the firstresponder for myView to
    >> the NSTextField does not help unfortunately.
    >
    > Probably the easiest approach would be to override
    > viewDidMoveToWindow on the view that will be in the menu, and from
    > within it call [[self window] makeFirstResponder:self];.
    > makeFirstResponder is one of a very few methods that is safe to call
    > on the menu window.
    >
    > -Peter

    ---
    Pierre Bernard
    http://www.bernard-web.com/pierre
    http://www.houdah.com
  • Hi!

    OK, I figured out how to add a timer. Unfortunately, that does not
    help with my problem of the misbehaving field editor.

    - (void)viewDidMoveToWindow
    {
    [super viewDidMoveToWindow];

    self.focusTimer = [NSTimer timerWithTimeInterval:1.0
                                                 target:self
              selector:@selector(focusOnSearchField)
              userInfo:nil
                                                repeats:NO];

    [[NSRunLoop currentRunLoop] addTimer:self.focusTimer
    forMode:NSEventTrackingRunLoopMode];
    }

    - (void)focusOnSearchField
    {
    [[self window] makeFirstResponder:searchField];

    [self.focusTimer invalidate];
    self.focusTimer = nil;
    }

    Pierre

    On 6 Feb 2008, at 00:43, Pierre Bernard wrote:

    > Hi Peter!
    > Hi Hendrik!
    >
    > I have almost the same setup as Hendrik: I use a NSSearchField in a
    > menu. When the menu is opened I want the focus to go to the search
    > field.
    >
    > At first sight, the solution suggested by Peter appears to work
    > fine. But something goes wrong. My search field misbehaves when I do
    > this.
    >
    > To be exact, the window's text editor does not respect the
    > properties of my search field. E.g. if I hit return while editing, I
    > get a newline in my search field. I however expect the search
    > field's action to be called.
    >
    > So I figured, I could delay setting the focus using
    > performSelector:afterDelay: or using a NSTimer. I wouldn't know if
    > this could alleviate the above described problem. The thing is: in
    > both cases my selector only gets called after the menu is dismissed.
    >
    > Hendrik, did you get this to work as expected?
    > Peter, could it be that the text editor is called upon too early?
    >
    > Best,
    > Pierre
    >
    > On 4 Jan 2008, at 21:30, Peter Ammon wrote:
    >
    >>
    >> On Jan 4, 2008, at 6:20 AM, Hendrik Holtmann wrote:
    >>
    >>> Hi everyone,
    >>>
    >>> I got another question regarding the new setView method in Leopard.
    >>> Let's assume I set the view for an NSMenuItem to myView. myView
    >>> contains an NSTextField. Now when I open the NSMenu I want to set
    >>> the focus on this textfield, so the user can directly enter some
    >>> text without having to click on the control first (like it works
    >>> in the spotlight menu). How can I achieve that? I know how to call
    >>> keyOrderAndFront and setFirstRespinder for NSWindows but how can I
    >>> do this with an NSMenu. Setting the firstresponder for myView to
    >>> the NSTextField does not help unfortunately.
    >>
    >> Probably the easiest approach would be to override
    >> viewDidMoveToWindow on the view that will be in the menu, and from
    >> within it call [[self window] makeFirstResponder:self];.
    >> makeFirstResponder is one of a very few methods that is safe to
    >> call on the menu window.
    >>
    >> -Peter
    >
    > ---
    > Pierre Bernard
    > http://www.bernard-web.com/pierre
    > http://www.houdah.com
    >
    >
    >

    - - -
    Houdah Software s. à r. l.
    http://www.houdah.com

    HoudahGeo: One-stop photo geocoding
    HoudahSpot: Powerful Spotlight frontend

    ---
    Pierre Bernard
    http://www.bernard-web.com/pierre
    http://www.houdah.com
  • On 06/02/2008, at 7:37 PM, Pierre Bernard wrote:

    > OK, I figured out how to add a timer. Unfortunately, that does not
    > help with my problem of the misbehaving field editor.
    >
    > - (void)viewDidMoveToWindow
    > {
    > [super viewDidMoveToWindow];
    >
    > self.focusTimer = [NSTimer timerWithTimeInterval:1.0
    > target:self
    > selector:@selector(focusOnSearchField)
    > userInfo:nil
    > repeats:NO];
    >
    > [[NSRunLoop currentRunLoop] addTimer:self.focusTimer
    > forMode:NSEventTrackingRunLoopMode];
    > }
    >
    > - (void)focusOnSearchField
    > {
    > [[self window] makeFirstResponder:searchField];
    >
    > [self.focusTimer invalidate];
    > self.focusTimer = nil;
    > }
    >
    > Pierre

    Hi,

    not having Leopard I could be just adding noise, but...

    Shouldn't your timer's selector method's signature be - (void)
    focusOnSearchField:(NSTimer *)aTimer ??  That is, the timer should be
    the argument to the method.

    From the (Tiger) docs:

    Discussion

    After seconds have elapsed, the timer fires, sending the message
    aSelector to target. The aSelector method has the following syntax:

    - (void)myTimerFireMethod:(NSTimer*)theTimer

    The timer passes itself as the argument to aSelector... [and more
    deleted]

    HTH,

    Ron
  • Hi Ron!

    It appears that both work. I guess it depends on whether you add the
    semi-colon to the selector or not.

    The timer was only a wild idea on how to work around the original
    problem with the window's field editor. I got the timer to work, but
    it does not solve the original problem.

    Best,
    Pierre

    On 6 Feb 2008, at 11:33, Ron Fleckner wrote:

    >
    > On 06/02/2008, at 7:37 PM, Pierre Bernard wrote:
    >
    >> OK, I figured out how to add a timer. Unfortunately, that does not
    >> help with my problem of the misbehaving field editor.
    >>
    >> - (void)viewDidMoveToWindow
    >> {
    >> [super viewDidMoveToWindow];
    >>
    >> self.focusTimer = [NSTimer timerWithTimeInterval:1.0
    >> target:self
    >> selector:@selector(focusOnSearchField)
    >> userInfo:nil
    >> repeats:NO];
    >>
    >> [[NSRunLoop currentRunLoop] addTimer:self.focusTimer
    >> forMode:NSEventTrackingRunLoopMode];
    >> }
    >>
    >> - (void)focusOnSearchField
    >> {
    >> [[self window] makeFirstResponder:searchField];
    >>
    >> [self.focusTimer invalidate];
    >> self.focusTimer = nil;
    >> }
    >>
    >> Pierre
    >
    >
    > Hi,
    >
    > not having Leopard I could be just adding noise, but...
    >
    > Shouldn't your timer's selector method's signature be -
    > (void)focusOnSearchField:(NSTimer *)aTimer ??  That is, the timer
    > should be the argument to the method.
    >
    > From the (Tiger) docs:
    >
    > Discussion
    >
    > After seconds have elapsed, the timer fires, sending the message
    > aSelector to target. The aSelector method has the following syntax:
    >
    > - (void)myTimerFireMethod:(NSTimer*)theTimer
    >
    > The timer passes itself as the argument to aSelector... [and more
    > deleted]
    >
    >
    >
    > HTH,
    >
    > Ron

    ---
    Pierre Bernard
    http://www.bernard-web.com/pierre
    http://www.houdah.com
  • On 06 Feb 2008, at 11:38, Pierre Bernard wrote:

    > Hi Ron!
    >
    > It appears that both work. I guess it depends on whether you add the
    > semi-colon to the selector or not.
    >
    > The timer was only a wild idea on how to work around the original
    > problem with the window's field editor. I got the timer to work, but
    > it does not solve the original problem.

    I had the same problem and I solved it more or less with the following
    approach:

    - use a custom view for the NSStatusItem. Using the standard setMenu
    approach, all sorts of redrawing and focus issues occur.
    - when a mouse click occurs in the NSStatusItem's view, I bring the
    application to front using [NSApp activateIgnoringOtherApps:YES]
    (because the application isn't necessarily the frontmost application
    when the NSStatusItem is clicked) and start a timer to fire after 0.01
    seconds
    - In the timer action, I pop up the menu, which causes the delegate
    method menuWillOpen to be called.
    - When the menu is being opened, I call [[self window]
    makeFirstResponder:textField] in the viewDidMoveToWindow method of the
    NSMenuItem's view (a custom view with a text field in it)
    - in menuWillOpen and menuDidClose I redraw the NSStatusItem's view
    using -drawStatusBarBackgroundInRect:withHighlight:

    So to recap, I needed:
    - A custom view for the NSStatusItem which fakes the standard view
    - A custom view for the NSMenuItem that tries to make the text field
    the first responder
    - All sorts of dirty hacks just to make sure the menu isn't popped up
    before the view is able to get focus

    As I said, this solves the problem "more or less". There are still
    redrawing issues, especially when the menu is longer than the screen
    height. But at least the view gets focus. And I think I might be able
    to solve the redrawing issues by calling needsDisplay after every
    event in the textfield, but still..

    Surely, there must be a better way to do this? I'm not sure these
    hacks will continue to work..

    Apple?

    --Lieven
previous month january 2008 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