2

1つのウィンドウにNSImageViewがあるアプリケーションがあります。ユーザーは任意のファイル/フォルダー(画像だけでなく)を画像ビューにドラッグアンドドロップできるはずなので、NSImageViewクラスをサブクラス化して、これらのタイプのサポートを追加しました。

通常のビューではなくNSImageViewを選択した理由は、ユーザーがファイルをドロップする準備ができた状態でホバーしたときに、アニメーション(たとえば、下向きで上下を指す矢印)も表示したかったためです。私の質問はこれです:これを行うための最良の方法(最も効率的、最速、最小のCPU使用率など)は何でしょうか?

実際、私はすでにそれを行っていますが、この質問をしたのは、0.02秒未満の速度で画像を変更するように設定すると、画像が遅れ始めるという事実です。これが私がそれをした方法です:

NSImageViewサブクラスの場合:

  • ivarがあります:NSTimer * animTimer;
  • awakeFromNibをオーバーライドし、[super awakeFromNib]を呼び出し、NSImageを使用して画像を配列(約45枚の画像)にロードします
  • ユーザーがファイルを入力するときはいつでも、頻度= 0.025(より少なくて遅れる)でanimTimerを開始し、配列内の次の画像を設定するセレクター(drawNextImageと呼ばれる)
  • ユーザーがドラッグアンドドロップを終了または終了するたびに、[animTimerinvalidate]を呼び出して画像の更新を停止します

サブクラスに画像を設定する方法は次のとおりです。

- (void)drawNextImage
{
    currentImageIndex++; // ivar / kNumberDNDImages is a constant defined as 46
    if (currentImageIndex >= kNumberDNDImages) { currentImageIndex = 0;}
    [super setImage: [imagesArray objectAtIndex: currentImageIndex]]; // imagesArray is ivar
}

それで、どうすればこれを十分に速く行うことができますか?周波数は約0.01秒にしたいのですが、遅れは0.025未満なので、今のところ設定しました。ああ、私の画像は正しいサイズ(+または-1ピクセルか何か)であり、.pngです(たとえば、透明度が必要です-jpegはそれを行いません)。

編集:

NSResponderの提案に従おうとしましたが、メソッドを次のように更新しました。

- (void)drawNextImage
{
    currentImageIndex++;
    if (currentImageIndex >= kNumberDNDImages) { currentImageIndex = 0;}
    NSRect smallImgRect;
    smallImgRect.origin = NSMakePoint(kSmallImageWidth * currentImageIndex, [self.bigDNDImage size].height); // Up left corner - ??
    smallImgRect.size = NSMakeSize(kSmallImageWidth, [self.bigDNDImage size].height);

    // Bottom left corner - ??
    NSPoint imgPoint = NSMakePoint(([self bounds].size.width - kSmallImageWidth) / 2, 0);

    [bigDNDImage drawAtPoint: imgPoint fromRect: smallImgRect operation: NSCompositeCopy fraction: 1];
}

また、このメソッドと他のドラッグアンドドロップメソッドをNSImageViewサブクラスから既に持っていたNSViewサブクラスに移動しました。スーパークラスとこのメソッドを除いて、すべてがまったく同じです。また、いくつかの定数を変更しました。

これの初期のテストでは、NSGraphicsContextなどについて話している実行を停止しなかったいくつかのエラー/警告メッセージを受け取りました。これらは今は消えていますが、ご存知のとおりです。なぜ登場したのか、どういう意味なのか全くわかりません。それらが再び現れる場合、私はそれらについて心配します、今ではありません:)

編集2:

これは私が今していることです:

- (void)drawNextImage
{
    currentImageIndex++;
    if (currentImageIndex >= kNumberDNDImages) { currentImageIndex = 0;}
    [self drawCurrentImage];
}
- (void)drawCurrentImage
{
    NSRect smallImgRect;
    smallImgRect.origin = NSMakePoint(kSmallImageWidth * currentImageIndex, 0); // Bottom left, for sure
    smallImgRect.size = NSMakeSize(kSmallImageWidth, [self.bigDNDImage size].height);

    // Bottom left as well
    NSPoint imgPoint = NSMakePoint(([self bounds].size.width - kSmallImageWidth) / 2, 0);

    [bigDNDImage drawAtPoint: imgPoint fromRect: smallImgRect operation: NSCompositeCopy fraction: 1];
}

そして、ここでの落とし穴は、drawRectが呼び出されたときにdrawCurrentImageを呼び出すことです(実際には、私が思っていたよりも簡単に解決できました)。

さて、私はこれを合成画像で試したことがないと言わなければなりません。なぜなら、40以上の画像を希望どおりに(次々に)マージするための適切で迅速な方法が見つからなかったからです。しかし、興味のない人のために、NSImageViewサブクラスと同じことをするようにこれを変更しました(配列から40以上の画像を読み取り、それらを表示します)、スピードバンプは見つかりませんでした:NSViewはNSImageViewと同じように0.025未満で遅れています。また、コアアニメーション(画像は彼女に指示した場所ではなく奇妙な場所に描画されます)を使用するときにいくつかの問題があり、NSGraphicsContextについて話しているいくつかの警告がありますが、解決方法がまったくわかりません(私は完全ですObjective-Cのツールを使用した描画などに関してはnoob)。したがって、これらすべての画像をマージしてNSViewで試す方法が見つからない限り、当面はNSImageViewを使用しています。

4

2 に答える 2

2

コアアニメーションはGPUですべてを実行するため、おそらく最も高速です。各画像のレイヤーを作成し、各レイヤーを各画像から作成contentsできるCGImageに設定し、それらすべてを単一のトップレベルレイヤーのサブレイヤーとして追加し、プレーンNSViewでトップレベルレイヤーをホストしてから、各画像を切り替えるだけです。レイヤーのhiddenプロパティを順番に。

于 2011-07-03T19:07:21.243 に答える
0

おそらく、すべてのコンポーネント イメージを 1 つの長いイメージに描画し、 を使用してセグメントをビューに描画し-drawAtPoint:fromRect:operation:fraction:ます。ただし、OpenGL に頼ることで、それよりも高速にできると確信しています。

于 2011-07-01T04:57:31.943 に答える