我如何在 window 的 canvas 上 paint/draw/render 一个点或给一个像素着色,而在 Mac OS X 上只有几行 Obj-C 使用Xcode?

How do I paint/draw/render a dot or color a pixel on the canvas of my window with only a few lines in Obj-C on Mac OS X using Xcode?

[编辑:]从我的项目的第一阶段开始:

我当前的 objective 非常简单(至少在抽象上如此):我想(重新)为空白中的像素着色 Mac OS X 应用程序 window。我想用尽可能少的代码行来经济地做到这一点,因为查看大块代码真的很碍眼。

我真的不想处理图像和图像缓冲区或绘制最小的可见线条和矩形,但我愿意尝试一下。最后,我阅读的 Whosebug 和 Apple Kit 文章多得数不过来。

原定议程是:

1) 访问我的空白应用程序 window 的“内容”

2) 在该内容中指定我感兴趣的像素

3) 使用其颜色空间值访问该像素

4) 如果可能直接重写值

看起来非常紧凑和简单,对吧?

这就是我的 AppDelegate 中发生的事情。我打开构造函数:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    /*
     For a more complex app, it's probably better to not put a window into the Main Menu NIB.
     Instead, make a separate NIB for the window.
     Then, load it using a window controller object and ask that for its window.
     */

    NSRect frame = [_window frame];
    frame.origin.x = 0;
    frame.origin.y = 0;
    frame.size.width = 1425;
    frame.size.height = 810;

    [_window setFrame: frame display: YES];

以下是我尝试绘制某种东西的尝试。

策略 #1 - NSRectFill:

NSRect pxl;
    pxl.origin.x = 0;
    pxl.origin.y = 0;
    pxl.size.width = 128;
    pxl.size.height = 128;
    //_window.draw(_ dirtyRect: pxl)
    NSRectFill(pxl);
    //draw(_ dirtyRect: pxl);

策略 #2(我真的不想尝试这个,因为它让我觉得既廉价又懒惰)- NSBezierPath:

NSBezierPath * path = [NSBezierPath bezierPath];
    [path setLineWidth: 4];
    NSPoint startPoint = {  0, 0 };
    NSPoint endPoint   = { 128, 128 };
    [path  moveToPoint: startPoint];
    [path lineToPoint: endPoint];
    [[NSColor redColor] set];
    [path stroke];

我知道我在这里画了一条线,但每一点都有帮助。

策略 #3 - 使用图像和图像表示对象:

NSImage * image;

    //create and define a colorspace object:
    NSColor * rgb = [NSColor colorWithDeviceRed:1.0f
                                green:1.0f
                                 blue:1.0f
                                alpha:1.0f];

    //load the defined colorspace data into image rep:
    NSBitmapImageRep * imgRep = [[NSBitmapImageRep alloc] initWithData:[image TIFFRepresentation]];
    [imgRep setColor:rgb atX:128.0 y:128.0];

当然,这个的问题是图像对象不包含任何东西。那我在里面放什么呢?我必须在那里加载 XIB 文件吗?我在网上看到了一些解决方案,它们打败了 "writing as few lines as possible" 的观点。

策略#4 - 使用复杂而冗长的函数:

NSColor *MyColorAtScreenCoordinate(CGDirectDisplayID displayID, NSInteger x, NSInteger y)
    { //Function definition is not allowed here
        CGImageRef image = CGDisplayCreateImageForRect(displayID, CGRectMake(x, y, 1, 1));
        NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:image];
        CGImageRelease(image);
        NSColor *color = [bitmap colorAtX:0 y:0];
        [bitmap release];
    }

然后它抱怨: Function definition is not allowed here 所以我用 - (void) 把这个带到了全球范围,但它还是抱怨: Expected method body

策略 #5 - 使用 bitmapImageRepForCachingDisplayInRect()

NSData *data;
    NSBitmapImageRep *rep;
    rep = [self bitmapImageRepForCachingDisplayInRect:[self frame]];
    [self cacheDisplayInRect:[self frame] toBitmapImageRep:rep];
    data = [rep TIFFRepresentation];

它给了我: No visible @interface for 'AppDelegate' declares the selector 'frame' 我不就是定义了同一范围内的框架吗?

我用这个关闭我的委托构造函数:

    [_window setFrame: frame display: YES];
}

超出我尝试的范围

策略 #6 - 自定义 drawRect():

- (void)drawRect:(NSRect)dirtyRect {
    // set any NSColor for filling, say white:
    [[NSColor whiteColor] setFill];
    NSRectFill(dirtyRect);
    [super drawRect:dirtyRect];
}
No visible @interface for 'NSObject' declares the selector 'drawRect:'

这是否意味着它不知道自己的drawRect函数?

策略 #7 - 从 Mac OS Cocoa: Draw a simple pixel on a canvas 复制并粘贴一大块:

NSInteger width = 128;
    NSInteger height = 128;
    NSInteger dataLength = width * height * 4;
    UInt8 *data = (UInt8*)malloc(dataLength * sizeof(UInt8));

    //Fill pixel buffer with color data
    for (int j=0; j<height; j++) {
        for (int i=0; i<width; i++) {

            //Here I'm just filling every pixel with red
            float red   = 1.0f;
            float green = 0.0f;
            float blue  = 0.0f;
            float alpha = 1.0f;

            int index = 4*(i+j*width);
            data[index]  =255*red;
            data[++index]=255*green;
            data[++index]=255*blue;
            data[++index]=255*alpha;

        }
    }

    // Create a CGImage with the pixel data
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    CGImageRef img = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,

                            provider, NULL, true, kCGRenderingIntentDefault);

    //Clean up
    CGColorSpaceRelease(colorspace);
    CGDataProviderRelease(provider);
    // Don't forget to free(data) when you are done with the CGImage

这些方法我都试过了;什么都没画。我在这里做错了什么吗?我的操作顺序错了吗?我试图让编译器和构建器都符合语法并易于理解。

旁注 1:我真的希望我能用尽可能少的 classes/objects 在空白 window 上放点东西。

旁注 2:我看了那么多 MVC 图,读了那么多文章,仍然不清楚什么是什么。我已经看到了如此多的代码片段,试图实现相同的目标,以至于很难相信有不止一种方法可以做一些基本的事情。

在 window 的帧内为像素着色的简单行为已经成为一个加载过度的冒险,标有过度利用缓冲区和对象 Xcode “无法识别”。

No visible @interface declares this selector.

为您的自定义绘图创建 NSView 子类:

@interface MyView : NSView
@end

@implementation MyView

- (void)drawRect:(NSRect)dirtyRect
{
    [[NSColor redColor] setFill];
    NSRectFill(dirtyRect);
}

@end

确保将其插入 AppDelegate.m 的顶层 - 也就是说, 任何其他 @interface@implementation 之外块。

创建您的视图实例并将其分配给您的 window:

的内容视图
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // ... Existing code that sets the window frame

    MyView* myView = [[MyView alloc] initWithFrame:self.window.contentView.bounds];
    self.window.contentView = myView;
}

Am I doing something wrong here? Is my order of operations wrong?

applicationDidFinishLaunching: 是一种委托方法,允许您响应应用程序生命周期的特定部分。这不是尝试绘制到屏幕的合适位置。考虑到您的应用程序可以有多个 windows,每个都包含多个视图或绘图表面。

Does that mean that it doesn't know its own drawRect function?

应用程序委托没有 drawRect 函数。

Then it complains: Function definition is not allowed here So I took this one out to the global scope with - (void) but it complains anyway: Expected method body

一些纯粹是建设性的反馈:看起来你最好从 C 或 Objective C 的初学者介绍开始,而不是直接跳入编程 AppKit。在不理解他们在做什么的情况下将代码块复制粘贴到 applicationDidFinishLaunching: 中不太可能获得您想要的结果。