Анимированный индикатор выполнения в NSMenuItem - PullRequest
1 голос
/ 03 ноября 2010

Я хочу поместить анимированный индикатор выполнения в NSMenuItem пользовательский вид.Это продемонстрировано в примере Apple MenuItemView , но он не анимируется (по крайней мере, не в 10.5, а в примере, очевидно, из 10.4).

Я попытался установить таймер, который вызываетsetNeedsDisplay:YES, запланировано как NSEventTrackingRunLoopMode, как говорят документы.Это работает, но только для определенного индикатора выполнения, если я изменяю значение, и только при первом открытии меню.Второй и последующие разы бар перерисовывается дважды, а затем остается замороженным.Для неопределенного индикатора выполнения полосы парикмахера никогда не оживляют.

Изменить: фрагмент кода.Я просто добавил вызов itemChanged, который, похоже, не дал никакого эффекта.Обновление только текстового элемента работает нормально.

class AppDelegate(NSObject):
  barItem = None
  menuProgressBar = None
  progressItem = None

  def applicationDidFinishLaunching_(self, sender):
    statusbar = NSStatusBar.systemStatusBar()
    self.statusitem = statusbar.statusItemWithLength_(
        NSSquareStatusItemLength)
    self.statusitem.setHighlightMode_(True)
    image = NSImage.imageNamed_("menubar.png")
    self.statusitem.setImage_(image)
    self.statusitem.retain()

    menu = NSMenu.alloc().init()

    AppDelegate.barItem = NSMenuItem.alloc(). \
        initWithTitle_action_keyEquivalent_('progress', None, '')
    itemView = NSView.alloc().initWithFrame_(NSMakeRect(0, 0, 50, 20))
    itemView.setAutoresizingMask_(NSViewWidthSizable)
    AppDelegate.menuProgressBar = \
        NSProgressIndicator.alloc().initWithFrame_(NSMakeRect(16, 5, 22, 10))
    AppDelegate.menuProgressBar.setAutoresizingMask_(NSViewWidthSizable)
    AppDelegate.menuProgressBar.setControlSize_(NSSmallControlSize)
    AppDelegate.menuProgressBar.setUsesThreadedAnimation_(True)
    itemView.addSubview_(AppDelegate.menuProgressBar)
    AppDelegate.menuProgressBar.setIndeterminate_(False)
    AppDelegate.menuProgressBar.setMaxValue_(100)
    AppDelegate.menuProgressBar.startAnimation_(self)
    timer = NSTimer.timerWithTimeInterval_target_selector_userInfo_repeats_(
        0.1, self,
        objc.selector(self.animateProgress, signature='v@:'),
        None, True)
    NSRunLoop.currentRunLoop().addTimer_forMode_(
        timer, NSEventTrackingRunLoopMode)
    AppDelegate.barItem.setView_(itemView)
    menu.addItem_(AppDelegate.barItem)

    AppDelegate.progressItem = NSMenuItem.alloc(). \
        initWithTitle_action_keyEquivalent_('Progress', None, '')
    menu.addItem_(AppDelegate.progressItem)

    self.statusitem.setMenu_(menu)

  def animateProgress(self):
    time = NSDate.timeIntervalSinceReferenceDate()
    AppDelegate.menuProgressBar.setDoubleValue_(time%100)
    AppDelegate.menuProgressBar.display()
    AppDelegate.progressItem.setTitle_('Progress: %d'%(time%100))
    AppDelegate.barItem.menu().itemChanged_(AppDelegate.barItem)

Ответы [ 2 ]

1 голос
/ 05 ноября 2010

Для неопределенного индикатора я отправляю сообщение startAnimation: в меню менюWillOpen: метод делегата, используя executeSelector: ... для отправки его в режиме NSEventTrackingRunLoopMode.

- (void)menuWillOpen:(NSMenu *)menu
{
  [[progressIndicator performSelector:@selector(startAnimation:)
                           withObject:self
                           afterDelay:0.0
                              inModes:[NSArray arrayWithObject:NSEventTrackingRunLoopMode]];
}

Для определенного индикатора я попробовал ваш код (но в target-C), и он сработал. Я не знаю python или PyObjC, но, глядя на код для переменной времени, я думаю, что вы отправляете вызов timeIntervalSinceReferenceDate () в класс NSDate. Так может время всегда ноль? На основании вызовов alloc () мне интересно, не должно ли это быть ...

time = NSDate.date (). TimeIntervalSinceReferenceDate ()


Обновление: здесь для записи приведен код, который я использовал для тестирования индикатора определенного прогресса. Просто obj-c версия кода ОП. Индикатор обновляется правильно.

- (void)menuWillOpen:(NSMenu *)menu
{
    NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(animateProgress:) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode];
}

- (void)animateProgress:(NSTimer *)timer
{
    NSTimeInterval time = [[NSDate date] timeIntervalSinceReferenceDate];
    [progressIndicator setDoubleValue:fmod(time, 100)];
}
1 голос
/ 03 ноября 2010

Таймерный подход должен быть совершенно ненужным.Вы сказали NSProgressIndicator -setUsesThreadedAnimation: YES, затем сказали -startAnimation:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...