NSMenuItem中的动画进度条

时间:2010-11-03 17:02:06

标签: cocoa pyobjc nsmenuitem

我想在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 个答案:

答案 0 :(得分:1)

计时器方法应该是完全没必要的。你告诉NSProgressIndicator -setUsesThreadedAnimation:YES然后告诉它-startAnimation:?

答案 1 :(得分:1)

对于一个不确定的指标,我在菜单的menuWillOpen:delegate方法中使用performSelector发送startAnimation:消息:...以NSEventTrackingRunLoopMode模式发送它。

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

对于确定性指标,我尝试了你的代码(但是在Objective-C中)并且它有效。我不知道python或PyObjC但是查看时间变量的代码我认为你正在向NSDate类发送timeIntervalSinceReferenceDate()调用。那么也许时间总是零?基于alloc()调用,我想知道它是不应该......

  

time = NSDate.date()。timeIntervalSinceReferenceDate()


更新:这里的记录是我用来测试确定进度指标的代码。只是对象的OP代码的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)];
}