2011-04-09 9 views
4

私は自分のアプリケーションのいずれかのUIをカスタマイズしています、とアイデアはときにフォーカスのうちテキスト領域を最初にグレーの縁取りされていることであり、それが焦点になると、ボーダーが明るく白くなります。私のアプリは暗いテーマを使用しており、一列に並んだNSTextFieldの場合、これは素晴らしいです。サブクラスNSScrollViewのdrawRect:メソッド

しかし私は、サブクラス化されNSTextViewの問題に実行していますよ。境界線を適切に変更するために、実際に親のサブクラスNSScrollViewをサブクラス化する必要がありましたが、依然として奇妙な動作が見られます。 (下のスクリーンショットを参照してください。)これは素敵な境界線を生成する、(単にテストのためである代わりに、充填、)ストロークのパスを私を許すように私は、全体のスクロールビューを埋めるために赤いボックスが欲しい。代わりに、赤いボックスは内部の子ビューにのみ塗りつぶすように見えます。 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

編集:おかげで彼の答えのためのジョシュ・キャスウェルへ。焦点が合っていないときと焦点が合っているときの適切な振る舞いについては以下を参照

No Focus

Focus

+0

境界線を常に完全に表示したいのですか、またはテキストビューの端が表示されている領域にのみ表示させますか? – ughoavgfhw

+0

良い質問です。スクロールビューの境界線の周りに、境界線が常に表示されるようにします。境界線は常に表示されますが、最初のレスポンダでないときは明るいグレーで、フォーカスがあると明るい白です。 (暗い背景にあります) –

+0

これはおそらくクリッピングの問題です。 'CGContextGetClipBoundingBox((CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]);'を使って現在のクリッピング矩形を見つけて、それを投稿します。 '[super drawRect:]'を呼び出さないことで問題を解決できるかもしれませんが、NSScrollViewは通常描画を行わないので大丈夫です。 – ughoavgfhw

答えて

7

ughoavgfhwが指摘したように、NSScrollViewは通常、任意の描画を行うには、おそらくその方法で、その子ビューとの奇妙な相互作用を持っていません。これは、それがフォーカスリングを描画する際のAppKitが何をするかの合理的な近似値である必要があり

// 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はビューの範囲外に描画することが許可されています - これは完全にであることを保証することはできませんが、遊ぶには3 pxのマージンがあるようです。あなたが望むならば、あなたは境界内に完全にリングを描くことができます。実際のフォーカスリングは、(ここでやったように)ビューの内側にわずかに(2 px)広がっています。

アップルのドキュメントSetting the Clipping Regionです。

編集:質問にご意見を再度読んだ後、私は長い間ったらしい-LYは本当の答えを埋めていて実感します。 NSClipViewをサブクラス化し、そのスクロールビューのクリップビューを切り替えるか、ドキュメントビューのカスタムビューを使用してください。


*:またNSScrollViewのドキュメントビューとして設定されたカスタムビューサブクラスの描画コードでこれを置くことができます。テキストビューはそのサブビューになる可能性があります。またはカスタムNSClipViewサブクラスに置き換えてください。

+0

パーフェクト - 私が実際にやらなければならなかったのは、スクロールビューの境界でNSBezier * clipPathを作成してからsetClipを呼び出すことでした!ありがとう! –

+0

@craig:役に立つ情報を素早く手に入れることができてうれしいです! –

+0

NSRect outerRect = NSInsetRect(bounds、-2、-2)を使用して、outerRectにNSInsetRectを再度使用できます。 –