スクロール時に NSCollectionView を再描画するとグラフィックが破損する
-
20-09-2019 - |
質問
軽度の刺激物が入っています NSCollectionView
その中で、 NSCollectionViewItem
ウィンドウをスクロールすると、視覚的に分割されます。
分割の速度はスクロールの速度によって異なります。たとえば、ゆっくりスクロールすると、別れが頻繁に発生します。高速スクロールはそれほどではありません。問題は、カスタム NSView の場合にあるようです。 NSCollectionViewItem
表示可能なフレームの境界を越えて使用しています。
My NSView (カスタム ビュー) NSCollectionViewItem
) は非常にシンプルな描画アルゴリズムを備えており、それほど複雑なものはありません。
基本的に、drawRect メソッドの DirtyRect 内にフレームを作成し、その中にいくつかのフレームを作成します。
-(void)drawRect:(NSRect)dirtyRect
{
NSRect mOuterFrame = NSMakeRect(dirtyRect.origin.x, dirtyRect.origin.y, 104, 94);
NSRect mSelectedFrame = NSInsetRect(mOuterFrame, 2, 2);
NSRect mRedFrame = NSInsetRect(mSelectedFrame, 2, 2);
NSRect mInnerFrame = NSInsetRect(mRedFrame, 2, 2);
NSBezierPath * mOuterFramePath = [NSBezierPath bezierPathWithRect:mOuterFrame];
NSBezierPath * mSelectedFramePath = [NSBezierPath bezierPathWithRect:mSelectedFrame];
NSBezierPath * mRedFramePath = [NSBezierPath bezierPathWithRect:mRedFrame];
NSBezierPath * mInnerFramePath = [NSBezierPath bezierPathWithRect:mInnerFrame];
[mainBackgroundColor set];
[mOuterFramePath fill];
if (selected)
[[NSColor yellowColor] set];
else
[mainBackgroundColor set];
[mSelectedFramePath fill];
if (isRedBorder)
[[NSColor redColor] set];
else
[mainBackgroundColor set];
[mRedFramePath fill];
[[NSColor blackColor] set];
[mInnerFramePath fill];
}
コードの前後でフォーカスをロックして解放したり、グラフィックスコンテキストを設定して復元したりしてみましたが、どれも問題を解決していないようです。
私は Snow Leopard を使用していますが、それが違いを生むとは思いません。
ソリューションのアップデート
興味のある方のために、NSResponder が推奨する問題の解決策をここに示します。イニシャルを作成していました mOuterFrame
に基づいて drawRect:
メソッド dirtyRect
指摘したように、これは間違った行為でした。以下からの簡単な変更:
NSRect mOuterFrame = NSMakeRect(dirtyRect.origin.x, dirtyRect.origin.y, 104, 94);
0 ベースの原点へ:
NSRect mOuterFrame = NSMakeRect(0, 0, 104, 94);
また、提案されているように、四角形のみを使用しているため、コードの効率も微調整しましたが、上記のコード変更自体は問題を解決するのに十分でした。2 ピクセルのラインを取得するには、変更を追加する必要がありました。新しい方法:
-(void)drawRect:(NSRect)dirtyRect
{
NSRect mOuterFrame = NSMakeRect(0, 0, 104, 94);
NSRect mSelectedFrame = NSInsetRect(mOuterFrame, 2, 2);
NSRect mRedFrame = NSInsetRect(mSelectedFrame, 2, 2);
NSRect mInnerFrame = NSInsetRect(mRedFrame, 2, 2);
[NSBezierPath setDefaultLineWidth:2.0];
[mainBackgroundColor set];
[NSBezierPath strokeRect:mOuterFrame];
if (selected)
[[NSColor yellowColor] set];
else
[mainBackgroundColor set];
[NSBezierPath strokeRect:mSelectedFrame];
if (isRedBorder)
[[NSColor redColor] set];
else
[mainBackgroundColor set];
[NSBezierPath strokeRect:mRedFrame];
[[NSColor blackColor] set];
[NSBezierPath strokeRect:mInnerFrame];
}
解決
私が最初に気づいは、あなただけの代わりに)NSFrameRect()とNSRectFillを(使用することができたときにパスの束を作成しているので、上記のコードは、かなり無駄であるということです。
第二に、あなたが描くものの形状は-drawRectに渡された四角形に依存すべきではない:.その長方形は、単に更新するエリアが何であるかを説明しますので、あなたのビューが複雑な場合描くために何を決定する際に、より効率的にすることができます。