Bizarre Custom View Rendering

Discussion in 'Mac Programming' started by stadidas, Jan 7, 2009.

  1. stadidas macrumors regular

    Joined:
    Feb 27, 2006
    Location:
    Kent, United Kingdom
    #1
    Hi everyone,

    I have come across a rather strange problem in a project that I am working on involving custom views. I currently have one view called AccountSummaryView, which draws a gradient background. It also contains a subview called GraphView, which currently just draws some lines with NSBezierPath.
    This is all working as expected and looks like this:

    [​IMG]

    However, if I click away to another application, this happens to the view:

    [​IMG]

    I have put log statements in, and it appears that the view is continuously redrawn with ever decreasing rectangles. Strangely, this only happens when I add the GraphView as a subview of AccountSummaryView, which I am doing like this:

    Code:
    - (id)initWithFrame:(NSRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            accountBalanceGraphView = [[GraphView alloc] initWithFrame:NSZeroRect];
        }
    	
    	[self addSubview:accountBalanceGraphView];
        return self;
    }
    
    If I remove the addSubview line, the redrawing does not occur. The AccountSummaryView drawRect looks like this:

    Code:
    - (void)drawRect:(NSRect)rect
    {
    	[self drawBackgroundGradientForRect:rect];
    	
            NSRect graphViewRect = NSMakeRect(0, 0, rect.size.width * 0.7, rect.size.height * 0.8);
    	graphViewRect.origin.x += (rect.size.width - graphViewRect.size.width - 10);
    	graphViewRect.origin.y += ((rect.size.height / 2) - (graphViewRect.size.height / 2));
    	
    	[accountBalanceGraphView setFrame:graphViewRect];
    }
    
    I can't see why adding a subview like this causes such bizarre behaviour. If I do the same thing in IB i.e create a custom view set to AccountSummaryView, and drop a GraphView into it, then it works perfectly well. However, I wish to control the GraphView programatically, so I would rather create it in code.

    If any of you Cocoa gurus could point me in the right direction I would be very grateful :)
     
  2. stadidas thread starter macrumors regular

    Joined:
    Feb 27, 2006
    Location:
    Kent, United Kingdom
    #2
    Having done a bit more testing, I have found that the cause of the repeated drawing appears to be the math being used to calculate the attributes of the graphViewRect. If any calculations are performed using the values from rect passed in to drawRect, the view is repeatedly redrawn with ever decreasing rects. I have changed drawRect in AccountSummaryView to look like this:

    Code:
    - (void)drawRect:(NSRect)rect
    {
    	[self drawBackgroundGradientForRect:rect];
            NSRect graphViewRect = NSMakeRect(0, 0, 400, 200);	
    	[accountBalanceGraphView setFrame:graphViewRect];
    }
    
    This prevents the strange redrawing effect shown above, but does not do what I want. As AccountSummaryView is resizable I would like the GraphView to resize as well. So my question now is how can I operate on the values of the rect passed in to draw rect to create a new NSRect that is proportionate to the original rect without all the strange redrawing behaviour?
     
  3. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #3
    The images aren't loading for me, so I'm not sure the main problem.

    However, I'm not sure if you're aware but the rect parameter passed to drawRect: is the coordinates of the view that need updating. If you have heavy drawing that needs optimization you'll want to use that parameter to only redraw what's needed. But most of the time you don't need this and just need to draw to the view's bounds via [self bounds]
     
  4. stadidas thread starter macrumors regular

    Joined:
    Feb 27, 2006
    Location:
    Kent, United Kingdom
    #4
    Fixed!

    I changed AccountSummaryView drawRect to look like this:

    Code:
    - (void)drawRect:(NSRect)rect
    {
    	[self drawBackgroundGradientForRect:rect];
            NSRect graphViewRect = NSMakeRect(0, 0, self.bounds.size.width * 0.7, self.bounds.size.height * 0.8);
    	graphViewRect.origin.x += (self.bounds.size.width - graphViewRect.size.width - 10);
    	graphViewRect.origin.y += ((self.bounds.size.height / 2) - (graphViewRect.size.height / 2));
    	
    	[accountBalanceGraphView setFrame:graphViewRect];
    }
    
    By using the views bounds and not accessing the rect in any way the repeat redrawing has been avoided.
     

Share This Page