tags:

views:

175

answers:

1

I'm having some very basic problems changing line color/width when drawing different lines (intended for a chart) with NSBezierPath. The following code should make it clear what I'm trying to do:

#import "DrawTest.h"

@implementation DrawTest

- (id)initWithFrame:(NSRect)frameRect
{
NSLog(@"in 'initWithFrame'...");
    if ((self = [super initWithFrame:frameRect]) != nil)
        {
    [self drawBaseline];
    [self display]; // ...NO!
    [self drawPlotline];
    }
return self;
}

- (void)drawBaseline
{
    NSRect windowRect;
    int width, height;

    windowRect = [self bounds];
    width = round(windowRect.size.width);
    height = round(windowRect.size.height);

    theLineWidth=1.0;
    [[NSColor grayColor] set];
    // allocate an instance of 'NSBezierPath'...
    path = [[NSBezierPath alloc]init];
    // draw a HORIZONTAL line...
    [path moveToPoint:NSMakePoint(0,height/2)];
    [path lineToPoint:NSMakePoint(width,height/2)];
}

- (void)drawPlotline
{
    theLineWidth=10.0;
    [[NSColor redColor] set];
    // draw a VERTICAL line...
    [path moveToPoint:NSMakePoint(100,125)]; // x,y
    [path lineToPoint:NSMakePoint(100,500)];
}

- (void)drawRect:(NSRect)rect
{
NSLog(@"in 'drawRect'...");
    // draw the path line(s)
    //  [[NSColor redColor] set];
    [path setLineWidth:theLineWidth];
    [path stroke];
}

- (void)dealloc
{
    [path release];
    [super dealloc];
}

@end

The problem obviously lies in the fact that 'drawRect' only gets called ONCE (after both methods have run), with the result that all lines appear in the last color and line width set. I've tried calling [self display] etc. in the hope of forcing 'drawRect' to redraw the NSView contents between the two method calls, but to no avail.

Can anyone suggest a basic strategy to achieve what I'm trying to do here, please? Any help would be much appreciated.

+2  A: 

Quick answer is: move [self drawBaseline] and [self drawPlotline] inside drawRect. Also, you need to call [path stroke] once per color, before changing the color. So, the pseudo-code is something like

-(void)drawRect:(NSRect)rect
{
      NSBezierPath*path1=...
      construct the path for color red...
      [[NSColor redColor] set];
      [path1 stroke]; 

      NSBezierPath*path2=...
      construct the path for color blue...
      [[NSColor blueColor] set];
      [path2 stroke]; 

}

Remember:

  • [path moveToPoint:] etc. does not draw the path. It just constructs the path inside the object. Once it's constructed, you stroke the path using [path stroke].

  • Also, the color is not the property of the path constructed inside the NSBezierPath instance. So, [color set] is not recorded inside your NSBezierPath instance! It's the property of the graphic context. Conceptually, 1. you construct the path. 2. you set the color to the context. 3. you stroke the path.

  • In Cocoa, it's not that you tell the system when to draw, when to refresh, etc. Cocoa tells you when to draw, by calling your drawRect:. The graphic context on which you draw is not available outside of drawRect:, unless you create off-screen context yourself. So, don't bother drawing beforehand. Just draw everything inside drawRect .

Yuji
Thanks Yuji, I appreciate your help. It's working great now :-)
Bender