Frage

Für einen Teil meiner Anwendung muss ich ein Bild einer bestimmten Ansicht und aller ihrer Unteransichten erstellen.

Dazu erstelle ich einen Kontext, der eine Bitmap mit der gleichen Größe wie die Ansicht umschließt, bin mir aber nicht sicher, wie ich die Ansichtshierarchie darin zeichnen soll.Ich kann eine einzelne Ansicht zeichnen, indem ich einfach den Kontext festlege und explizit drawRect aufrufe, aber das betrifft nicht alle Unteransichten.

Ich kann in der NSView-Benutzeroberfläche nichts sehen, was dabei helfen könnte, daher vermute ich, dass die Lösung auf einer höheren Ebene liegt.

War es hilfreich?

Lösung

Ich habe festgestellt, dass das Schreiben des Zeichencodes selbst der beste Weg ist, um Folgendes zu erreichen:

  • Beheben Sie potenzielle Transparenzprobleme (einige der anderen Optionen fügen dem gesamten Bild einen weißen Hintergrund hinzu).
  • Die Leistung war viel besser

Der folgende Code ist nicht perfekt, da er sich nicht mit Skalierungsproblemen beim Übergang von Grenzen zu Frames befasst, aber er berücksichtigt den isFlipped-Status und funktioniert sehr gut für das, wofür ich ihn verwendet habe.Beachten Sie, dass nur die Unteransichten (und die Unterunteransichten, ...) gezeichnet werden.rekursiv), aber es auch dazu zu bringen, sich selbst zu zeichnen, ist sehr einfach, fügen Sie einfach a hinzu [self drawRect:[self bounds]] Bei der Umsetzung von 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;
}

Andere Tipps

Sie können verwenden -[NSView dataWithPDFInsideRect:] um die gesamte Hierarchie der Ansicht, an die Sie sie senden, in einer PDF-Datei darzustellen, die als zurückgegeben wird NSData Objekt.Anschließend können Sie damit machen, was Sie wollen, einschließlich der Umwandlung in eine Bitmap.

Sind Sie sicher, dass Sie eine Bitmap-Darstellung wünschen?Schließlich könnte dieses PDF (zumindest theoretisch) auflösungsunabhängig sein.

Sie können verwenden -[NSBitmapImageRep initWithFocusedViewRect:] Nachdem Sie den Fokus auf eine Ansicht gesperrt haben, wird die Ansicht selbst (und ihre Unteransichten) in das angegebene Rechteck gerendert.

Was Sie tun möchten, ist bereits explizit verfügbar.Weitere Informationen finden Sie im Abschnitt „NSView Drawing Redirection API“ in den Versionshinweisen zu 10.4 AppKit.

Erstellen Sie ein NSBitmapImageRep zum Zwischenspeichern und löschen Sie es:

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

Cache dazu:

-[NSView cacheDisplayInRect:toBitmapImageRep:]

Wenn Sie allgemeiner in einen bestimmten Kontext zeichnen möchten, um Ansichtsrekursion und Transparenz korrekt zu handhaben,

-[NSView displayRectIgnoringOpacity:inContext:]

Ja, für diese spezielle Verwendung sind die unskalierten Bilddaten genau das, was ich brauche.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top