Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 使用NSImageView快速连续显示多个图像_Objective C_Cocoa_Performance_Nstimer_Nsimageview - Fatal编程技术网

Objective c 使用NSImageView快速连续显示多个图像

Objective c 使用NSImageView快速连续显示多个图像,objective-c,cocoa,performance,nstimer,nsimageview,Objective C,Cocoa,Performance,Nstimer,Nsimageview,我有一个应用程序,其中一个窗口中有一个NSImageView。用户应该能够将任何文件/文件夹(不仅仅是图像)拖放到图像视图中,因此我将NSImageView类子类化以添加对这些类型的支持 我之所以选择NSImageView而不是普通视图,是因为我还想在用户将文件悬停在上面准备放置时显示动画(比如一个向下并上下移动的箭头)。我的问题是:做这件事的最佳方式是什么(最高效、最快、CPU使用最少等等) 事实上,我已经这样做了,但让我问这个问题的是,当我设置图像以低于0.02秒的速度变化时,它开始滞后。我

我有一个应用程序,其中一个窗口中有一个NSImageView。用户应该能够将任何文件/文件夹(不仅仅是图像)拖放到图像视图中,因此我将NSImageView类子类化以添加对这些类型的支持

我之所以选择NSImageView而不是普通视图,是因为我还想在用户将文件悬停在上面准备放置时显示动画(比如一个向下并上下移动的箭头)。我的问题是:做这件事的最佳方式是什么(最高效、最快、CPU使用最少等等)

事实上,我已经这样做了,但让我问这个问题的是,当我设置图像以低于0.02秒的速度变化时,它开始滞后。我是这样做的:

在NSImageView子类中:

- (void)drawNextImage
{
    currentImageIndex++; // ivar / kNumberDNDImages is a constant defined as 46
    if (currentImageIndex >= kNumberDNDImages) { currentImageIndex = 0;}
    [super setImage: [imagesArray objectAtIndex: currentImageIndex]]; // imagesArray is ivar
}
  • 有一个ivar:NSTimer*animTimer
  • 重写awakeFromNib,调用[super awakeFromNib]并使用NSImage将图像加载到数组中(大约45个图像)
  • 每当用户输入文件时,启动频率为0.025的animTimer(较小且滞后),以及设置阵列中下一个图像的选择器(称为drawNextImage)
  • 每当用户退出或结束拖放时,调用[animTimer invalidate]停止更新图像
下面是我在子类中设置图像的方式:

- (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多个图像。但对于ineterested,我修改了它,使其与我的NSImageView子类做相同的事情(从数组中读取40多个图像并显示它们),我没有发现减速:NSView与NSImageView一样滞后于0.025以下。此外,我在使用核心动画时发现了一些问题(图像是在奇怪的地方绘制的,而不是我告诉她的地方)和一些关于NSGraphicsContext的警告,我根本不知道如何解决这些问题(我完全不知道如何使用Objective-C的工具来绘制等等)。因此,目前我正在使用NSImageView,除非我找到一种方法来合并所有这些图像并尝试使用NSView。

我可能会将所有组件图像绘制成一个长图像,并使用
-drawAtPoint:fromRect:operation:fraction:
将片段绘制到视图中。不过,我相信通过使用OpenGL,您可以使其速度更快。

核心动画可能是最快的,因为它可以在GPU上完成所有工作。为每个图像创建一个层,将每个层的
内容设置为可以从每个图像生成的CGImage,将它们全部添加为单个顶层层的子层,然后依次切换每个图像层的
隐藏
属性。

这里我不明白的一件事是(0,0)点在哪里。NSImage的默认(0,0)点是什么:左上、右上、左下或右下?视图的(0,0)点也是如此。它在哪里?我需要这个来计算drawAtPoint:和fromRect:的值,我假设NSImage使用左上角,视图使用左下角,但它不工作。我已经更新了我的问题,以显示我现在在做什么。@Alex Truppel:它在左下角,除非它不是(
isFlipped
istrue)。有一个例外是你自己没有设置NSScreens的帧,它的原点在左上角。另一种加快速度的方法是将合成图像设置为CGLayer。这些都是为了一次又一次地绘制而存在的。@peter我发现我的图像根本不显示的解决方案(这是我在询问坐标时遇到的问题):我忘了在drawrect上绘制它,所以我只绘制了一次,然后图像就消失了。关于CGLayer,我不知道,因为我确实画过多次图像,但问题是图像每次都会改变。如果我正确理解了文档,那么这对速度没有好处。不过,我可能错了。@Alex Truppel:是的,您需要在
drawRect:
中完成所有视图绘制,或者响应从那里直接发送的消息。至于CGLayer,我特别提到了“合成图像”,指的是NSResponder建议将所有图像合成为一个图像。您能否提供一个示例?“将所有图层添加为单个顶层图层的子图层”部分的内容让我无法理解。@Charlie:对于每个图像,创建一个图层,并将图层的
内容设置为CGImage,然后将所有这些图层添加为一个父图层的子图层。将该层设置为NSView的层。实际上,我最终使它工作了。。。除了不使用
自动重定尺寸任务
。然而,我把它贴到了它自己的问题上。