2

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

我选择 NSImageView 而不是普通视图的原因是因为我还想在用户将鼠标悬停在准备删除的文件上时显示动画(比如指向向下和上下移动的箭头)。我的问题是:什么是最好的方法(最有效、最快、最少的 CPU 使用率等)来做到这一点?

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

在 NSImageView 子类中:

  • 有一个 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,所以这就是我目前设定的。哦,我的图像尺寸正确(+ 或 - 一个像素或其他东西)并且它们在 .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工具进行绘图等方面的菜鸟)。所以目前我正在使用 NSImageView,除非我找到一种方法来合并所有这些图像并尝试使用 NSView。

4

2 回答 2

2

Core Animation 可能是最快的,因为它会在 GPU 上完成所有工作。为每个图像创建一个图层,将每个图层设置contents为您可以从每个图像制作的 CGImage,将它们全部添加为单个顶级图层的子图层,在普通 NSView 中托管顶级图层,然后只需切换每个图像层的hidden属性依次。

于 2011-07-03T19:07:21.243 回答
0

我可能会将所有组件图像绘制成一个长图像,并使用-drawAtPoint:fromRect:operation:fraction:. 不过,我相信您可以通过使用 OpenGL 来加快速度。

于 2011-07-01T04:57:31.943 回答