0
votes

Right now I have two windows. One of them has an NSView, which acts as a background color and the other one has a colorwell that changes a color variable in a shared instance.

My program sort of works. I can open my colorwell window and select a color, but the background color only updates if I manually resize the window.

I tried to get past this issue by having a thread in the background looping:

[self setNeedsDisplay:YES];
[self updateLayer];
[self display];

I'm not completely sure that those 3 lines are necessary, but I am sure that they are re-calling my drawRect method.

I even threw an NSLog into the drawRect method to test. I saw in the console that it was getting called over-and-over again.

Here is my drawRect method:

- (void)drawRect:(NSRect)dirtyRect{

        [theDATA.main_frame_background_color setFill];
        [NSBezierPath fillRect:dirtyRect];

}

theDATA.main_frame_background_color is an NSColor from a shared instance. I am positive that the value is changing because my NSView updates when I resize the window.

I'm completely clueless on why this is not working. Hope you can help.

2
You should never call display method manually. Have you tried NSRectFill instead of [NSBezierPath fillRect:]? Have you checked if the color is really changed?Sega-Zero
Also, if your view is layer-backed, have you changed it's layerContentsRedrawPolicy property to NSViewLayerContentsRedrawOnSetNeedsDisplay? The default value is NSViewLayerContentsRedrawNever.Sega-Zero
@Sega-Zero Thanks so much! You don't want to know how long I spent trying to troubleshoot this issue. Setting the layerContentsRedrawPolicy was a start. I found out that setNeedsDisplay wasn't thread safe for some crazy reason so I used an auxiliary method(as seen in my answer to this question).Doug Beney
Posted an answer, so you could accept it. Also, if your drawing is just a color fill, you may find useful CALayer's property backgroundColor =)Sega-Zero

2 Answers

0
votes

First, never call a display method directly. Mark dirty area with setNeedsDisplay: and the view will be redrawn after a while. If your view is layer-backed, be aware of layerContentsRedrawPolicy property, since it's default value is NSViewLayerContentsRedrawNever. There's no way to automatically determine which policy fit your needs best, so this property should be set manually.

0
votes

I solved my problem thanks to @Sega-Zero's suggestion of using layerContentsRedrawPolicy and through a bit of research I found out that I couldn't directly call setNeedsDisplay in a thread, so I used performSelectorOnMainThread.

My Thread class:

- (void)updateLOOP{
    while (true){      

            [self performSelectorOnMainThread: @selector(refreshClock)
                                   withObject: nil
                                waitUntilDone: NO];

            [NSThread sleepForTimeInterval:.1];
        }
    }
}

External update method:

- (void) refreshClock{
    [self setNeedsDisplay:YES];
}

Now everything works as it should. The drawRect method is getting called without having to use [self display].