2

Is there a way to close the NSComboBox popup programmatically?

There seem to be a bug with NSComboBox when the popup is open, and the control get's removed and then released. For some reason, the dealloc of the NSComboBox doesn't clear the popup before destructing.

Edit: Just to clarify - this bug only happens when the popup list is opened. Otherwise the control is released properly and cleanly.

Edit Edit: This is how to reproduce it.

  • Create a new Cocoa application.
  • Turn off automatic reference counting.
  • In @(applicationDidFinishLaunching) create a new NSComboBox and store it to a member.
  • Add the combo box to the window's contentView.
  • Create a new menu item with a keyboard shortcut and bind to a selector.
  • In the menu item's selector: remove the combo box from the view and release the member. Don't forget to set it back to nil.
  • Run the application.
  • Click on the combo box to show the popup up.
  • Use the shortcut to remove the combo box.
AndyTang
  • 547
  • 7
  • 24
  • I would assume that calling `abortEditing` would close it. I'm not sure what you are saying about "not clearing the popup before destructing". the popup is part of the `NSComboBox` so surely that must be released. are you somehow retaining it? – Brad Allred Sep 23 '14 at 16:02
  • Yes, you are right that the control should destroy the popup when released, but it isn't - which I think it's a bug. It's easy to replicate with a clean project. – AndyTang Sep 23 '14 at 16:48
  • @(abortEditing) does work! However it leaves the popup hanging around as it hasn't closed it - but it doesn't crash anymore since it's not trying to access something that's already been removed due to @(abortEditing) cleaning some things up. – AndyTang Sep 23 '14 at 16:49
  • so at first i thought this could be solved by using `removeFromSuperviewWithoutNeedingDisplay` and `autorelease` instead of `release`, but that didnt work... curious – Brad Allred Sep 23 '14 at 17:59
  • I suspect the popup has a unretained pointer back to the NSComboBox which isn't being cleaned up on dealloc. I guess Combo Box are not commonly used in OSX, in favour of the NSPopupButtons. – AndyTang Sep 23 '14 at 20:53
  • if you enable `NSZombie` you can see the backtrace for the call. the problem is that the `NSComboboxCell` calls `trackMouse:inRect:ofView:untilMouseUp` which is going to try to call a method on the `NSComboBox` when tracking ends, but you delete the box in the middle of tracking. – Brad Allred Sep 23 '14 at 21:09
  • Yes, that's what I gather. But the dealloc should have cancel the tracking and cleaned up after itself. The problem is, I have no way to stop the tracking externally neither. – AndyTang Sep 24 '14 at 08:57
  • It seems that the @(trackMouse:) is overridden by NSComboBoxCell, so it never calls @(continueTracking:). So I can't actually use that either to stop tracking on destruction. :( – AndyTang Sep 24 '14 at 10:28
  • its about time I ask the question of *why* you are deleting a control dynamically like this. why not just hide it? odds are if you are creating it once you will need it again right? – Brad Allred Sep 24 '14 at 14:31
  • I have a panel that dynamically creates a set of controls based on a 'context' hence the deletion. Usually it isn't a problem since the popup is forced to close when you click anywhere else. But I also have a menu item shortcut that changes the context - so the panel destroys its current set of controls and repopulates. NSComboBox is the only control that do not clean up after itself if a popup is shown. I can change the way it all works of course to avoid this issue - or maybe I should just not use the NSComboBox at all. – AndyTang Sep 24 '14 at 14:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/61847/discussion-between-brad-allred-and-andytang). – Brad Allred Sep 24 '14 at 14:57

1 Answers1

-2

You can perform a check in your code or grey out menu items by using the NSComboBox delegate methods -comboBoxWillPopUp: and -comboBoxWillDismiss: to control a BOOL.

The BOOL property can be used to control enabling of the menu item.

Set the delegate of the combo box.

To the interface of the delegate add

@property BOOL itemEnabled;

and to the implementation add

- (void)comboBoxWillPopUp:(NSNotification *)notification {
    self.itemEnabled = NO;
}
- (void)comboBoxWillDismiss:(NSNotification *)notification {
    self.itemEnabled = YES; //re-enabled when dismissed
}

Set initial value of itemEnabled to YES.

In the xib bind the Enabled attribute of the menu item to the delegate and the Model Key Path set to self.itemEnabled

mikeD
  • 185
  • 1
  • 6