2

I create a NSStatusItem and add an image. After the image has been added, changing the image.template property has no immediate effect on the icon. Only after clicking the status item does the image become a template. Is there a way to force the system to redraw the status item/bar?

I put together the simple example, pressing the 'test' button changes the image to a template, but the change doesn't take effect until the status icon is selected.

-(void)awakeFromNib{
    // Setup status item
    statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
    statusMenu = [[NSMenu alloc] initWithTitle:@""];
    menuItem = [[NSMenuItem alloc] initWithTitle:@"test"
                                   action:nil
                                   keyEquivalent:@""];
    
    NSImage* img = [NSImage imageNamed:@"aubergine.png"];
    img.template = true;
    img.size = NSMakeSize(18.0, 18.0);
    statusItem.button.image = img;
    
    [statusItem setMenu:statusMenu];
    [statusMenu addItem:menuItem];

    // Add button to window
    NSButton* button = [[NSButton alloc] initWithFrame:NSMakeRect(10, 10, 50, 20)];
    [[window contentView] addSubview: button];
    [button setTitle: @"Test"];
    
    [button setTarget:self];
    [button setAction:@selector(buttonPressed)];
}

-(void)buttonPressed {
    [[[statusItem button] image] setTemplate: false];
}
Kyle Berezin
  • 597
  • 4
  • 20
  • Can't you set `image.template` before adding the image? Post your code please. – Willeke Aug 20 '20 at 07:04
  • 1
    Most controls assume images are immutable. If you mutate the image, try simply setting the `image` property again, or cycle it (set it to `nil` then the image again) to convince the view to redraw. – James Bucanek Aug 20 '20 at 16:19
  • @Willeke it's part of a 3rd party API, so yes it can be set before adding the image, but the API must allow it to also occur afterward. The code is buried here, but we'll amend the original example with a reproducible example shortly. https://github.com/AdoptOpenJDK/openjdk-jdk11u/compare/master...Vzor-:master – tresf Aug 20 '20 at 18:50
  • @Willeke I just posted an example, The issue is this is for an API that connects to java. I would like a way to be able to change the property at any time. I could do a ugly fix to get it to think there is a new image entirely, but I would prefer to do it with a redraw function or makeDirty. – Kyle Berezin Aug 20 '20 at 22:09
  • 2
    See [needsDisplay](https://developer.apple.com/documentation/appkit/nsview/1483360-needsdisplay?language=objc). – Willeke Aug 21 '20 at 07:17
  • 1
    @Willeke Setting needsDisplay of the statusItem's button fixed it! Put it up as an answer and I will accept it. – Kyle Berezin Aug 21 '20 at 19:17

1 Answers1

1

As provided by Willeke in the comments, the solution is to use the needsDisplay property. The working function is:

-(void)buttonPressed {
    [[[statusItem button] image] setTemplate: false];
    [[statusItem button] setNeedsDisplay: true];
}
Kyle Berezin
  • 597
  • 4
  • 20