我如何在 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:
中不太可能获得您想要的结果。
[编辑:]从我的项目的第一阶段开始:
我当前的 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:
中不太可能获得您想要的结果。