Показывать меню 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) сегмент;
Другие вопросы по тегам