2011-04-09 5 views
4

내 앱 중 하나의 UI를 사용자 정의하고 있는데, 초점이 맞지 않으면 처음에는 텍스트 영역이 회색 테두리로되어 있고 초점이 맞으면 경계가 밝은 흰색이됩니다. 내 응용 프로그램은 어두운 테마를 사용하며, 한 줄로 된 NSTextField의 경우이 기능이 훌륭합니다.NSScrollView를 서브 클래 싱하기 drawRect : 메서드

서브 클래스가 NSTextView 인 문제가 있습니다. 국경을 적절히 변경하기 위해 실제로 부모 하위 클래스 NSScrollView을 서브 클래스해야했지만 이상한 행동을 보았습니다. (아래 스크린 샷을 참조하십시오.) I 전체 스크롤보기를 채우기위한 빨간색 상자가 필요합니다.이 방법을 사용하면 경로를 테스트 할 수있는 채우기 대신에 멋진 테두리를 만들 수 있습니다. 대신 빨간색 상자는 내부 하위보기 만 채우는 것처럼 보입니다. NSScrollView 서브 클래스입니다

다음 코드 : 아래와 같이

- (void)drawRect:(NSRect)dirtyRect { 
    [super drawRect:dirtyRect]; 

    NSRect borderRect = self.bounds; 
    borderRect.origin.y += 1; 
    borderRect.size.width -= 1; 
    borderRect.size.height -= 4; 

    BOOL inFocus = ([[self window] firstResponder] == self); 

    if (!inFocus) { 
     inFocus = [self anySubviewHasFocus:self]; 
    } 

    if (inFocus) { 
     [[NSColor colorWithDeviceRed:.8 green:.2 blue:0 alpha:1] set]; 
    } else { 
     [[NSColor colorWithDeviceRed:.1 green:.8 blue:0 alpha:1] set]; 
    } 

    [NSGraphicsContext saveGraphicsState]; 
    [[NSGraphicsContext currentContext] setShouldAntialias:NO]; 
    [NSBezierPath fillRect:borderRect]; 
    [NSGraphicsContext restoreGraphicsState]; 

    NSLog(@"My bounds: %@", NSStringFromRect(borderRect)); 
    NSLog(@"Super (%@) bounds: %@", [self superview], NSStringFromRect(borderRect)); 
} 

은 스크린 샷을 생성합니다. 또한 로그의 출력을 확인하십시오. 에서 전체보기를 채워야한다고 제안합니다. 이것은 내부에있는 텍스트의 크기에 관계없이 지금까지 보여준 유일한 출력입니다. 캐리지 리턴을 입력하면 빨간색 상자의 높이가 증가하지만 출력은 다릅니다. (그리고 전체 경계를 채우기 위해 빨간색 상자를하고 싶습니다.)

2011-04-08 21:30:29.789 MyApp[6515:903] My bounds: {{0, 1}, {196, 87}} 
2011-04-08 21:30:29.789 MyApp[6515:903] Super (<EditTaskView: 0x3a0b150>) bounds: {{0, 1}, {196, 87}} 

Drawing Issue

편집 : 덕분에 그의 대답에 대한 조쉬 캐스 웰합니다. 집중하지 않을 때와 집중했을 때의 올바른 행동은 아래를보십시오. Focus

+0

테두리를 항상 완전히 보시겠습니까, 아니면 텍스트보기의 가장자리가 보이는 영역에만 보이게할까요? – ughoavgfhw

+0

좋은 질문입니다. 스크롤 뷰 경계를 경계로 항상 경계선을 표시하고 싶습니다. 테두리는 항상 표시되지만 첫 번째 응답자가 아닌 경우 밝은 회색이되고 포커스가있는 경우 밝은 흰색이됩니다. (어두운 배경에 있습니다.) –

+0

이것은 클리핑에 문제가있는 것 같습니다. 'CGContextGetClipBoundingBox ((CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]);)를 사용하여 현재 클리핑 rect를 찾고 그것이 무엇인지 게시하십시오. '[super drawRect :]'를 호출하지 않아도 문제를 해결할 수 있습니다. NSScrollView는 대개 아무 그림도 그리지 않기 때문에 괜찮습니다. – ughoavgfhw

답변

7

ughoavgfhw가 언급 한 바와 같이

No Focus

, NSScrollView은 일반적으로 어떤 그림을, 그리고 아마도 그 방법으로 자식 경관을 감상 할 수있는 이상한 상호 작용을 가지고하지 않습니다. 난 당신이 * 원하는이 사용자 정의 포커스 링을 그릴 텍스트 뷰의 도면 코드에서 다음과 같은 것을 넣는 게 좋을 것 :
// We're going to be modifying the state for this, 
// so allow it to be restored later 
[NSGraphicsContext saveGraphicsState]; 

// Choose the correct color; isFirstResponder is a custom  
// ivar set in becomeFirstResponder and resignFirstResponder 
if(isFirstResponder && [[self window] isKeyWindow]){ 
    [myFocusedColor set]; 
} 
else { 
    [myNotFocusedColor set]; 
} 

// Create two rects, one slightly outset from the bounds, 
// one slightly inset 
NSRect bounds = [self bounds]; 
NSRect innerRect = NSInsetRect(bounds, 2, 2); 
NSRect outerRect = NSMakeRect(bounds.origin.x - 2, 
           bounds.origin.y - 2, 
           bounds.size.width + 4, 
           bounds.size.height + 4); 

// Create a bezier path using those two rects; this will 
// become the clipping path of the context 
NSBezierPath * clipPath = [NSBezierPath bezierPathWithRect:outerRect]; 
[clipPath appendBezierPath:[NSBezierPath bezierPathWithRect:innerRect]]; 

// Change the current clipping path of the context to 
// the enclosed area of clipPath; "enclosed" defined by 
// winding rule. Drawing will be restricted to this area. 
// N.B. that the winding rule makes the order that the 
// rects were added to the path important. 
[clipPath setWindingRule:NSEvenOddWindingRule]; 
[clipPath setClip]; 
// Fill the rect; drawing is clipped and the inner rect 
// is not drawn in 
[[NSBezierPath bezierPathWithRect:outerRect] fill]; 
[NSGraphicsContext restoreGraphicsState]; 

그것이 초점 링을 그릴 때 AppKit의가하는 일의 합리적인 근사치해야한다. 물론 AppKit은 뷰 경계 밖으로 그릴 수 있습니다. 은 완전히 안전함을 보장 할 수는 없지만 3 픽셀의 여백이있는 것 같습니다. 원한다면 경계 안쪽으로 완전히 그릴 수 있습니다. 어쨌든 뷰 내부에서 실제 포커스 링이 약간 (2 픽셀) 확장됩니다 (여기에서했던 것처럼).

애플 문서 Setting the Clipping Region.

편집 : 질문에 대한 귀하의 의견을 다시 읽은 후에, 나는 오랫동안 실마리가되어 실제 답변을 묻어 버렸다는 것을 알고 있습니다. NSClipView을 서브 클래스 화하고 스크롤보기의 클립보기를 전환하거나 문서보기에 대한 사용자 정의보기를 사용하십시오.


* : 또한 NSScrollView의 문서보기로 설정 사용자 지정보기 서브 클래스의 드로잉 코드에 넣고 있었다; 텍스트 뷰는 그 서브 뷰일 수 있습니다. 또는 사용자 정의 NSClipView 서브 클래스로 대체하십시오.

+0

완벽 - 실제로 스크롤 뷰의 경계를 가진 NSBezier * clipPath를 만든 다음 setClip을 호출해야했습니다. 감사! –

+0

@craig : 유용한 정보를 다룰 수있어서 다행입니다! –

+0

NSRect outerRect = NSInsetRect (bounds, -2, -2)를 사용하여 outerRect에 NSInsetRect를 다시 사용할 수 있습니다. –