Изменение заливки на уже нарисованный NSBezierPath - PullRequest
0 голосов
/ 18 декабря 2009

Я бы хотел изменить заливку кнопки, которую нарисовал (подкласс NSButton)

Вот код, который я уже получил:

- (void)drawRect:(NSRect)dirtyRect {
// Drawing code here.
// Create the Gradient 
NSGradient *fillGradient = [[NSGradient alloc] initWithStartingColor:[NSColor lightGrayColor] endingColor:[NSColor darkGrayColor]];
// Create the path
aPath = [NSBezierPath bezierPath];

[aPath moveToPoint:NSMakePoint(10.0, 0.0)];
[aPath lineToPoint:NSMakePoint(85.0, 0.0)];
[aPath lineToPoint:NSMakePoint(85.0, 20.0)];
[aPath lineToPoint:NSMakePoint(10.0, 20.0)];
[aPath lineToPoint:NSMakePoint(0.0, 10.0)];
[aPath lineToPoint:NSMakePoint(10.0, 0.0)];

[fillGradient drawInBezierPath:aPath angle:90.0];
[fillGradient release];
}

- (void)mouseDown:(NSEvent *)theEvent {
    NSGradient *fillGradient = [[NSGradient alloc] initWithStartingColor:[NSColor lightGrayColor] endingColor:[NSColor darkGrayColor]];
    [fillGradient drawInBezierPath:aPath angle:-90.0];
}

и я получаю сигнал EXC_BAD_ACCESS. Как бы я это сделал?

Ответы [ 3 ]

6 голосов
/ 18 декабря 2009

Причиной EXC_BAD_ACCESS является следующая строка:

aPath = [NSBezierPath bezierPath];

создает автоматически освобожденный bezierPath, который будет освобожден в конце текущей итерации цикла выполнения. Чтобы избежать ошибки, вам нужно изменить ее на:

aPath = [[NSBezierPath bezierPath] retain];

Однако вы подходите к проблеме с неправильной стороны. Рисование должно выполняться только методом -drawRect: (или методами, которые вызываются только из -drawRect:). Вместо того чтобы пытаться рисовать в своем методе mouseDown:, вы должны создать новую переменную экземпляра BOOL для вашего класса (называемую, например, mouseIsDown) и установить ее в mouseDown:. Затем используйте это логическое значение, чтобы определить, как заполнить кнопку:

- (void)drawRect:(NSRect)aRect {
    NSGradient *fillGradient = nil;
    if (mouseIsDown)
        fillGradient = [[NSGradient alloc] initWithStartingColor:[NSColor lightGrayColor] endingColor:[NSColor darkGrayColor]];
    else
        fillGradient = [[NSGradient alloc] initWithStartingColor:[NSColor lightGrayColor] endingColor:[NSColor darkGrayColor]];

    // Do the rest of your drawRect method

}

- (void)mouseDown:(NSEvent *)theEvent {
    mouseIsDown = YES;
    [self setNeedsDisplay:YES];
}

- (void)mouseUp:(NSEvent *)theEvent {
    mouseIsDown = NO;
    [self setNeedsDisplay:YES];
}
1 голос
/ 18 декабря 2009

Это не имеет прямого отношения к вашему вопросу, но заголовок вашего вопроса опровергает ложное предположение, на которое я хочу ответить.

Изменение заливки на уже нарисованный NSBezierPath

Это невозможно.

В Какао «заливка» - это глагол, а не свойство объекта, как в Illustrator или Lineform. Вы не устанавливаете заполнение пути и не меняете его позже; Вы заполняете путь, и вы меняете это пикселями в каком-то невидимом хранилище. В реальной аналогии можно было бы установить сплайны на плоском стекле, затем заполнить область, ограниченную сплайнами, краской и дать ей высохнуть. «Заполнение» не является свойством сплайнов; это акт выливания краски в форму, которую они определяют.

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

Все это относится ко всем операциям рисования, включая обводку контуров и рисование растровых изображений. Рисование текста тоже, поскольку это просто еще один случай заполнения и / или обводки контура.

* Хорошо, вы, вероятно, могли бы удалить настоящую краску с реального стекла, химически или соскобом. Никакая аналогия не идеальна. ☺

0 голосов
/ 18 декабря 2009

Сохраните aPath после его создания, поскольку к моменту отправки сообщения mouseDown: оно будет равно autoreleased. Просто убедитесь, что release это в вашем классе dealloc или в другом месте, где это будет уместно.

Edit:

См. Ответ Мэтта Болла.

...