Я не могу правильно расположить NSTextField на диаграмме, нарисованной NSBezierPath

Я начинающий программист Cocoa. Я хочу программно разместить Cocoa NSTextField (подпредставление пользовательского представления) рядом с геометрической диаграммой, нарисованной в пользовательском представлении в программе, которая будет разработана с помощью XCode 4.3.2 для OS X на Lion. Чтобы упростить пример моей проблемы, предположим, что диаграмма должна быть рамкой, охватывающей текстовое поле (в дополнение к рамке или границе, доступной с NSTextField, и дальше; на самом деле моя диаграмма должна быть более сложной). Я обнаружил, что текстовое поле и поле не совпадают, как я ожидал (см. пример кода ниже). Почему?

Я сделал простой проект, не основанный на документах, в качестве диагностического примера, в котором я перетащил пользовательское представление в окно приложения, добавил приведенный ниже код и выполнил подключение из IBOutlet к представлению:

AnAppDelegate.h:

#import <Cocoa/Cocoa.h>

@interface AnAppDelegate : NSObject <NSApplicationDelegate> {
    IBOutlet NSView *view;
    NSRect textFieldRect;
    NSTextField *textField;
    NSBezierPath *box;
}

@property (assign) IBOutlet NSWindow *window;

@end

AnAppDelegate.m:

#import "AnAppDelegate.h"

@implementation AnAppDelegate

@synthesize window = _window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    textFieldRect = NSMakeRect(100, 100, 100, 20);
    textField = [[NSTextField alloc] initWithFrame:textFieldRect];

    NSRect frame = [textField frame];
    NSLog(@"frame %f %f %f %f", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);

    NSRect bounds = [textField bounds];
    NSLog(@"bounds %f %f %f %f", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);

    // Draw the text field
    [textField setStringValue:@"My text field"];
    [textField setBezeled:YES];
    [textField setDrawsBackground:NO];
    [textField setEditable:YES];
    [textField setSelectable:YES];
    [view addSubview:textField];

    // Draw a box (rectangle) around the text field
    //NSRect boxRect = [textField frame];
    box = [[NSBezierPath alloc] init];
    //boxRect.origin.x += 10;
    //boxRect.origin.y += 10;
    //boxRect.size.width += 20;
    //boxRect.size.height += 20;
    [box appendBezierPathWithRect:[textField frame]]; // :boxRect];
    [box stroke];

}

@end

Когда эта программа запущена, поле кажется смещенным влево и ниже текстового поля, по-видимому, на высоту текстового поля в каждом измерении. Я ожидаю, что он появится «под» подвидом NSTextField и будет скрыт им. (Конечно, в производственной программе это неразумно.)

Теперь, чтобы приблизиться к тому, что я хочу, если раскомментировать закомментированные строки исходного кода выше (добавив boxRect к пути к блоку вместо рамки текстового поля), то мой блок появится на 10 единиц впереди текста кадр - но я ожидал, что для этого мне нужно было добавить -10 единиц к происхождению, а не +10 единиц.

Что здесь происходит?


person user1336031    schedule 16.04.2012    source источник


Ответы (1)


Не углубляясь в позиционирование, здесь необходимо решить несколько более серьезных проблем. Вы неправильно используете систему рисования Какао. Вы не можете (как правило) просто начать рисовать (как это делает [box stroke]) в любом случайном месте вашего приложения. Вам нужен графический контекст.

Для рисования на экране вы помещаете свой код в метод -drawRect: пользовательского представления. Фреймворки обязательно настроят соответствующий контекст перед вызовом этого метода, а затем удалят контекст.

Я немного удивлен, что ваш код вообще работает, но в нем нет четко определенного графического контекста, поэтому у нас нет возможности узнать, какая здесь соответствующая система координат; рисунок в основном происходит где-то случайным образом. Рефакторинг вашего кода в соответствии с Руководством по рисованию Cocoa. и вы можете получить лучшие результаты.

Кстати, вы комментируете

// Draw the text field

Нет! Вы не рисуете текстовое поле; это делается фреймворками для вас во время следующего хода цикла выполнения, когда вызываются различные представления -drawRect:. Вы добавляете представление в иерархию представлений. Это не педантичная разница: вы можете манипулировать иерархией представлений самое большее (*) в любое время. Обычно рисовать можно только в -drawRect:.

(*): Многопоточность усложняет дело, но это, вероятно, не имеет значения, если вы только начинаете Cocoa.

person Conrad Shultz    schedule 16.04.2012
comment
Конрад, спасибо. Хотя я потратил день, пытаясь понять, почему у меня есть смещение, я только что заметил, что мой вид расположен в (20, 20) в окне. Если я изменю это, смещение изменится соответственно. Но я исправлю ситуацию в целом, как вы предлагаете. - person user1336031; 16.04.2012
comment
Это не будет иметь значения в -drawRect:, так как системы координат будут совпадать. (Вы редко используете систему координат окна.) Исправьте общие проблемы, и смещение исчезнет. - person Conrad Shultz; 16.04.2012