Рисование иерархии вида в конкретном контексте в Какао

Для части моего приложения мне нужно создать изображение определенного представления и всех его подпредставлений.

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

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

18.08.2008 16:34:01
5 ОТВЕТОВ
РЕШЕНИЕ

Я обнаружил, что написание кода для рисования самостоятельно было лучшим способом:

  • иметь дело с потенциальными проблемами прозрачности (некоторые другие опции добавляют белый фон ко всему изображению)
  • производительность была намного лучше

Приведенный ниже код не идеален, потому что он не решает проблемы масштабирования при переходе от границ к фреймам, но учитывает состояние isFlipped и очень хорошо работает для того, для чего я его использовал. Обратите внимание, что он рисует только подпредставления (и подпредставления, ... рекурсивно), но заставить его также нарисовать себя очень легко, просто добавьте a [self drawRect:[self bounds]]в реализацию imageWithSubviews.

- (void)drawSubviews
{
    BOOL flipped = [self isFlipped];

    for ( NSView *subview in [self subviews] ) {

        // changes the coordinate system so that the local coordinates of the subview (bounds) become the coordinates of the superview (frame)
        // the transform assumes bounds and frame have the same size, and bounds origin is (0,0)
        // handling of 'isFlipped' also probably unreliable
        NSAffineTransform *transform = [NSAffineTransform transform];
        if ( flipped ) {
            [transform translateXBy:subview.frame.origin.x yBy:NSMaxY(subview.frame)];
            [transform scaleXBy:+1.0 yBy:-1.0];
        } else
            [transform translateXBy:subview.frame.origin.x yBy:subview.frame.origin.y];
        [transform concat];

        // recursively draw the subview and sub-subviews
        [subview drawRect:[subview bounds]];
        [subview drawSubviews];

        // reset the transform to get back a clean graphic contexts for the rest of the drawing
        [transform invert];
        [transform concat];
    }
}

- (NSImage *)imageWithSubviews
{
    NSImage *image = [[[NSImage alloc] initWithSize:[self bounds].size] autorelease];
    [image lockFocus];
    // it seems NSImage cannot use flipped coordinates the way NSView does (the method 'setFlipped:' does not seem to help)
    // Use instead an NSAffineTransform
    if ( [self isFlipped] ) {
        NSAffineTransform *transform = [NSAffineTransform transform];
        [transform translateXBy:0 yBy:NSMaxY(self.bounds)];
        [transform scaleXBy:+1.0 yBy:-1.0];
        [transform concat];
    }
    [self drawSubviews];
    [image unlockFocus];
    return image;
}
2
15.09.2008 20:54:28

Вы можете использовать -[NSView dataWithPDFInsideRect:]для отображения всей иерархии представления, в которое вы отправляете его, в PDF, возвращенный как NSDataобъект. Затем вы можете делать с этим все, что пожелаете, в том числе отображать его в растровое изображение.

Вы уверены, что хотите растровое представление? В конце концов, этот PDF может быть (по крайней мере, теоретически) независимым от разрешения.

2
18.08.2008 17:19:03

Да, для этого конкретного использования немасштабированные данные изображения - именно то, что мне нужно.

0
18.08.2008 18:55:18

Вы можете использовать -[NSBitmapImageRep initWithFocusedViewRect:]после блокировки фокуса на представлении, чтобы представление само отображалось (и его подпредставления) в данный прямоугольник.

1
19.08.2008 01:25:23
Если представление находится в NSScrollView, это имеет побочный эффект - отображение содержимого представления обрезано до того, что видно в представлении прокрутки, и включает любые полосы прокрутки.
Jason 22.09.2015 22:21:34

То, что вы хотите сделать, уже доступно в явном виде. См. Раздел «API перенаправления чертежа NSView» в заметках о выпуске 10.4 AppKit.

Создайте NSBitmapImageRep для кеширования и очистите его:

NSGraphicsContext *bitmapGraphicsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:cacheBitmapImageRep];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:bitmapGraphicsContext];
[[NSColor clearColor] set];
NSRectFill(NSMakeRect(0, 0, [cacheBitmapImageRep size].width, [cacheBitmapImageRep size].height));
[NSGraphicsContext restoreGraphicsState];

Кеш к нему:

-[NSView cacheDisplayInRect:toBitmapImageRep:]

Если вы хотите более широко рисовать в заданном контексте обработки рекурсии и прозрачности представления правильно,

-[NSView displayRectIgnoringOpacity:inContext:]
1
10.06.2013 15:51:27
Ссылка для "API перенаправления чертежа NSView" в 10.4 developer.apple.com/mac/library/releasenotes/Cocoa/…
Matthieu Cormier 26.02.2010 01:15:34