Question

I have created a view and in my draw rect method I create paths depending on what a user does with sliders. Using standard colors , everything works and looks very nice. I am trying to follow a code snippet from apple that shows how to draw patterns into a rect at this link: Apple Drawing Guide

The example shows how to create a function callback with the pattern desired and then an additional method call to draw the rect. If I call the code as it is written from my rect it will draw my pattern as I would expect, however, I do not want to fill my rect , I want to fill a specified path in the rect. If I change the call in the drawing method from CGContextFillRect to CGContextFillPath, it doesn't work. I'm sure there is something I am overlooking to modify this code to get it to do what I want.

My callback pattern is a simple checkerboard:

code:

// Call Back function for Graphics Pattern

#define PATTERN_SIZE 10

void patternSpec(void *info , CGContextRef pContext){

    NSLog(@"patternSpec Callback Called");
    CGFloat subUnit = PATTERN_SIZE / 2;

    CGRect square1 = {{0,0}, {subUnit, subUnit}},
    square2 = {{subUnit, subUnit}, {subUnit, subUnit}},
    square3 = {{0 , subUnit}, {subUnit, subUnit}},
    square4 = {{subUnit , 0}, {subUnit, subUnit}};


    CGContextSetRGBFillColor(pContext, 1.0, 0.0, 0.0, 1.0 );
    CGContextFillRect(pContext, square1);

    CGContextSetRGBFillColor(pContext, 1.0, 0.0, 0.0, 1.0 );
    CGContextFillRect(pContext, square2);

    CGContextSetRGBFillColor(pContext, 0.0, 0.0, 0.0, 1.0 );
    CGContextFillRect(pContext, square3);

    CGContextSetRGBFillColor(pContext, 0.0, 0.0, 0.0, 1.0 );
    CGContextFillRect(pContext, square4);

}

// Method that draws the pattern

static void drawPattern (CGContextRef myContext)
{
    NSLog(@"drawPattern Called ");
    CGPatternRef    pattern;
    CGColorSpaceRef patternSpace;
    CGFloat         alpha = 1.0;
    //width, height;

    static const CGPatternCallbacks callbacks = {0, &patternSpec, NULL};

    CGContextSaveGState (myContext);
    patternSpace = CGColorSpaceCreatePattern (NULL);// 6
    CGContextSetFillColorSpace (myContext, patternSpace);// 7
    CGColorSpaceRelease (patternSpace);// 8

    pattern = CGPatternCreate (NULL,CGRectMake (0, 0, PATTERN_SIZE, PATTERN_SIZE),
    CGAffineTransformIdentity, PATTERN_SIZE, PATTERN_SIZE,
    kCGPatternTilingConstantSpacing true, &callbacks);

    CGContextSetFillPattern (myContext, pattern, &alpha);// 17
    CGPatternRelease (pattern);// 18
    //CGContextFillRect(myContext, rect);
    CGContextDrawPath(myContext, kCGPathFill);
    CGContextRestoreGState (myContext);

}

Here is a snippet of the code where I would like to call the routine:

CGContextSetLineWidth(context, .7);
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);


// Standard non-inverted view scenario.
CGContextBeginPath(context);

CGContextMoveToPoint(context, 0.00 , bMargin);      
CGContextAddLineToPoint(context, highPX - curveSP , bMargin);
[self addCurve:context startX:highPX startY:bMargin radius:bo curveSp:curveSP curveDir:FL_BL];

CGContextAddLineToPoint(context, highPX, ((h - tMargin) - curveSP) );
[self addCurve:context startX:highPX startY: (h - tMargin) radius:bo curveSp:curveSP curveDir:FL_TL];


CGContextAddLineToPoint(context, (lowPX - curveSP), (h - tMargin) );
[self addCurve:context startX: lowPX  startY: (h - tMargin) radius:bo curveSp:curveSP curveDir:FL_TR];

CGContextAddLineToPoint(context, lowPX, (bMargin + curveSP) );      
[self addCurve:context startX:lowPX startY: bMargin  radius:bo curveSp:curveSP curveDir:FL_BR];

CGContextAddLineToPoint(context, w, bMargin);

//CGContextDrawPath(context, nonInvertedView);

CGContextDrawPath(context, kCGPathStroke);
// fill with pattern
drawPattern(context);

The actual apple example also includes an NSRect arg in the drawing method, but since I don't want to fill a rect, I figured I could omit that. not sure though.

Thanks

Était-ce utile?

La solution

CGContextDrawPath resets the current path. (They used to mention that somewhere, but I couldn't find it in a quick search.)

Save the graphics state before you stroke, then restore before you fill with the pattern.

(I assume you're specifically trying to get an outer stroke by stroking and then filling over half of it. If you want or can accept a centered stroke, kCGPathFillStroke will do the job with a single CGContextDrawPath call.)

Autres conseils

So heres an update: I don't fully understand whats happening, but if I drop the code in the drawPattern method into a test app with an empty rect, it draws just like it should. If I drop the code into my method for drawing a path into a view , I get very strange behavior; it even tries to redraw parts of the view controller it should't even know about.

As soon as I deleted the CGContextSaveGState() , CGColorSpaceRelease(), CGPatternRelease(), and the CGContextRestoreGState(), the code started doing exactly what I wanted. I modified the method to this:

static void drawPattern(CGContextRef *pContext){

    static CGPatternRef    pattern;
    static CGColorSpaceRef patternSpace;
    static CGFloat         alpha = 1.0;


static const CGPatternCallbacks callbacks = {0, &patternSpec, NULL};

    patternSpace = CGColorSpaceCreatePattern (NULL);
    CGContextSetFillColorSpace (pContext, patternSpace);

    pattern = CGPatternCreate (NULL, 
               CGRectMake (0, 0, PATTERN_SIZE, PATTERN_SIZE),
               CGAffineTransformIdentity,
               PATTERN_SIZE, 
               PATTERN_SIZE, 
               kCGPatternTilingConstantSpacing,
               true, &callbacks);


     CGContextSetFillPattern (pContext, pattern, &alpha);   

}

Now I can either call the defined pattern, or set a define fill color:

CGContextSetFillColor(context);
or:    
drawPattern(context);

I would appreciate input on this, because I would like to know if leaving out some of these saveState or Release methods is a problem such as memory leaks.

Thanks

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top