Как нарисовать / нарисовать / визуализировать точку или раскрасить пиксель на холсте моего окна с помощью всего лишь нескольких линий в Obj- C на Ma c OS X с использованием Xcode? - PullRequest
0 голосов
/ 11 февраля 2020

[Edit:] Переход от фазы 1 моего проекта здесь: Как мне переопределить размер / происхождение окна приложения в коде, переопределяя параметры файла nib / xib, с Obj- C, Xcode 11.3.1 на Ма c OS X 10.15.2 (Каталина)?

Моя текущая цель довольно проста (по крайней мере, в резюме): я хочу (повторно) раскрасить пиксель в моем пустом окне приложения Ma c OS X. Я хочу сделать это экономно, используя как можно меньше строк кода, потому что смотреть на большие куски кода - настоящая заноза.

Я действительно не хотел иметь дело с изображениями и буферами изображений или рисовать мельчайшие видимые линии и прямоугольники, но я был готов попробовать все это. В итоге я прочитал больше статей о StackOverflow и Apple Kit, чем Бог может сосчитать.

Первоначальная повестка дня заключалась в следующем:

1) получить доступ к «содержимому» моего пустого окна приложения

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];

Ниже приведены мои попытки нарисовать что-то вроде.

Tacti c # 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);

Tacti c # 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];

Я знаю, что я рисую линию здесь, но каждый кусочек помогает.

Tacti c # 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? Я видел некоторые решения в сети, и они побеждают «писать как можно меньше строк».

Tacti c # 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

Tacti c # 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];
}

Вне этой области я пробовал

Tacti c # 6 - custom 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?

Tacti c # 7 - копирование и вставка большого фрагмента из Ma c OS Какао: нарисуйте простой пиксель на холсте :

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

Я попробовал каждый из этих методов; ничего, доктор aws. Я что-то здесь не так делаю? Мой порядок операций неправильный? Я пытался сохранить все это синтаксически совместимым и понятным для компилятора и сборщика.

Примечание 1: Я действительно хочу sh, чтобы я мог использовать как можно меньше классов / объектов, чтобы поместить что-то в пустое окно.

Примечание 2: Я видел так много MVC диаграмм и прочитал так много статей, что до сих пор неясно, что и для чего. Я видел столько кусков кода, как попытки достичь той же цели, что трудно поверить, что существует несколько способов сделать что-то фундаментальное.

Простой акт окраски пикселя в рамке окна превратился в загруженное приключение, помеченное чрезмерно используемыми буферами и объектами, которые Xcode «не распознает».

No visible @interface declares this selector.

1 Ответ

1 голос
/ 11 февраля 2020

Создайте NSView подкласс для своего пользовательского чертежа:

@interface MyView : NSView
@end

@implementation MyView

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

@end

Убедитесь, что он вставлен на верхнем уровне вашего AppDelegate.m, то есть вне любого другие блоки @interface и @implementation.

Создайте экземпляр своего представления и назначьте его представлению содержимого своего окна:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // ... Existing code that sets the window frame

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

Я что-то не так делаю Вот? Мой порядок операций неправильный?

applicationDidFinishLaunching: - это метод делегата, позволяющий вам реагировать на определенную c часть жизненного цикла приложения. Это не то место, где можно пытаться рисовать на экране. Учтите, что в вашем приложении может быть несколько windows, каждое из которых содержит несколько видов или поверхностей рисования.

Означает ли это, что он не знает свою собственную функцию drawRect?

Делегат приложения не имеет функции drawRect.

Затем он жалуется: определение функции здесь не разрешено. Поэтому я перенес это в глобальную область с помощью - (void), но он все равно жалуется: Ожидаемое тело метода

Некоторая обратная связь, которая предназначена как чисто конструктивный: кажется, что лучше начать с введения новичков в C или Objective C, а не прыгать прямо в программирование AppKit. Копирование фрагментов кода в applicationDidFinishLaunching: без понимания того, что они делают, вряд ли когда-нибудь даст желаемый результат.

...