Показывать меню NSSegmentedControl при щелчке сегмента, несмотря на то, что установлено действие
У меня есть NSSegmentedControl на моем интерфейсе с 4 кнопками. Элемент управления связан с методом, который будет вызывать разные методы в зависимости от того, какой сегмент нажат:
- (IBAction)performActionFromClick:(id)sender {
NSInteger selectedSegment = [sender selectedSegment];
NSInteger clickedSegmentTag = [[sender cell] tagForSegment:selectedSegment];
switch (clickedSegmentTag) {
case 0: [self showNewEventWindow:nil]; break;
case 1: [self showNewTaskWindow:nil]; break;
case 2: [self toggleTaskSplitView:nil]; break;
case 3: [self showGearMenu]; break;
}
}
Сегмент 4 имеет меню, прикрепленное к нему в методе awakeFromNib. Я бы хотел, чтобы это меню выпадало, когда пользователь нажимает на сегмент. На данный момент, он будет только выпадать, если пользователь нажимает и удерживает в меню. Из моих онлайн-исследований это связано с действием.
В настоящее время я работаю над этим, используя некоторый код, чтобы получить исходную точку элемента управления сегментом, и выскакиваю контекстное меню, используя NSMenu popUpContextMenu:withEvent:forView
но это довольно странно и выглядит плохо по сравнению со стандартным поведением, когда меню выпадает ниже сегментированной контрольной ячейки.
Есть ли способ, с помощью которого я могу сделать раскрывающееся меню, как и должно, после одного щелчка мышью, вместо того, чтобы заниматься хакерским контекстным меню?
4 ответа
Я не уверен ни в каком встроенном способе сделать это (хотя это действительно явная дыра в API NSSegmentedControl).
Моя рекомендация - продолжать делать то, что вы делаете, открывая контекстное меню. Однако вместо простого использования источника сегментированного элемента управления вы можете расположить его непосредственно под сегментом (как вам нужно), выполнив следующие действия:
NSPoint menuOrigin = [segmentedControl frame].origin;
menuOrigin.x = NSMaxX([segmentedControl frame]) - [segmentedControl widthForSegment:4];
// Use menuOrigin where you _were_ just using [segmentedControl frame].origin
Она не идеальна и не идеальна, но должна выполнять свою работу и придавать вид / поведение, которого ожидают пользователи.
(кроме того, NSSegmentedControl действительно нуждается в -rectForSegment:
метод)
Подкласс NSSegmentedCell, переопределите метод ниже и замените класс ячейки в IB. (Не требует никаких частных API).
- (SEL)action
{
//this allows connected menu to popup instantly (because no action is returned for menu button)
if ([self tagForSegment:[self selectedSegment]]==0) {
return nil;
} else {
return [super action];
}
}
Это Swift-версия ответа от J Hoover и мода от Adam Treble. Переопределение не было таким интуитивным, как я думал, так что, надеюсь, это поможет кому-то еще.
override var action : Selector {
get {
if self.menuForSegment(self.selectedSegment) != nil {
return nil
}
return super.action
}
set {
super.action = newValue
}
}
widthForSegment: возвращает ноль, если размер сегмента автоматически изменяется. Если вас не интересуют недокументированные API, существует rectForSegment:
- (NSRect) rectForSegment: (NSInteger) сегмент inFrame:(NSRect) кадр;
Но чтобы ответить на исходный вопрос, более простой способ получить немедленное всплывающее меню - это создать подкласс NSSegmentedCell и вернуть 0 для (опять же, без документов)
- (Двойной)_menuDelayTimeForSegment:(NSInteger) сегмент;