Anfängerfrage: Wie wird ein Custom View richtig eingesetzt?

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Anfängerfrage: Wie wird ein Custom View richtig eingesetzt?

    Ich habe mal wieder ein grundlegendes Verständnisproblem (Oder wieder einmal eine ganz dumme Frage!):
    Ich habe eine eigene Klasse von NSView abgeleitet, im Interface Builder ein Custom View erzeugt und im Identity Inspector meine Klasse MyView ausgewählt.
    initWithFrame und drawRect sind angelegt und funktionieren. Weiterhin sind Propertys und Setter implementiert.
    Jetzt mein Problem:
    Ich möchte über einen Setter ein Daten-Objekt an die Klasse übergeben, das durch drawRect gezeichnet werden soll.
    Wie bekomme ich aber eine Instanz meiner Klasse, die im Interface Builder bereits erzeugt und initialisiert wurde? initWithFrame und drawRect funktioniert ja schon.
  • Das habe ich probiert:
    IBOutlet MyView *myProfilView;

    und dann über einen Button:

    Quellcode

    1. - (IBAction)myButton:(id)sender {
    2. [myProfilView setI: 100];
    3. [myProfilView display];
    4. }


    Und schon schmiert die Anwendung im drawRect ab, weil die im initWithFrame initialisierten Objekte ungültig sind!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von LarsKrachen ()

  • Ich hoffe den View neu zeichnen und drawRect aufrufen.

    In InitWithFrame lege ich einige Pfade (NSBezierPath) an. Hier wird ein Koordinatensystem für die spätere Ausgabe als Pfad hinterlegt.
    In drawRect wird dann nur noch gezeichnet. Später sollen weitere Datenobjekte (Polygone), die über die Setter der Klaase hinzugefügt werden, gezeichnet werden.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von LarsKrachen ()

  • UIView? Ich habe von NSView abgeleitet.

    display
    Displays the receiver and all its subviews if possible, invoking each of the NSView methods lockFocus, drawRect:, and unlockFocus as necessary.

    - (void)display
    Discussion
    If the receiver isn’t opaque, this method backs up the view hierarchy to the first opaque ancestor, calculates the portion of the opaque ancestor covered by the receiver, and begins displaying from there.

    Availability
    • Available in OS X v10.0 and later.

    See Also

    Related Sample Code

    Declared In
    NSView.h


    Hier MyVieh.h:

    Quellcode

    1. #import <Cocoa/Cocoa.h>
    2. @interface MyView : NSView {
    3. @private
    4. NSInteger i;
    5. NSRect drawRect;
    6. NSBezierPath* drawPath;
    7. NSPoint pur, pul, por, pol;
    8. }
    9. @property NSInteger i;
    10. @end
    Alles anzeigen
  • Upps! Das habe ich geändert. Es hat sich aber nichts am Verhalten geändert.
    Hier noch einmal mein Code:

    MyView.h

    Quellcode

    1. #import <Cocoa/Cocoa.h>
    2. @interface MyView : NSView {
    3. @private
    4. NSInteger i;
    5. NSRect myDrawRect;
    6. NSBezierPath* drawPath;
    7. NSPoint pur, pul, por, pol;
    8. }
    9. @property NSInteger i;
    10. @end
    Alles anzeigen



    MyView.m:

    Quellcode

    1. #import "MyView.h"
    2. @implementation MyView
    3. @synthesize i;
    4. - (id)initWithFrame:(NSRect)frame
    5. {
    6. self = [super initWithFrame:frame];
    7. if (self) {
    8. // Initialization code here.
    9. i = 0;
    10. myDrawRect = [self bounds];
    11. CGFloat dxr = 30.5;
    12. CGFloat dyu = 20.5;
    13. CGFloat dxl = 30.5;
    14. CGFloat dyo = 5.5;
    15. pul.x = myDrawRect.origin.x+dxl;
    16. pul.y = myDrawRect.origin.y+dyu;
    17. pur.x = pul.x+myDrawRect.size.width-dxl-dxr;
    18. pur.y = pul.y;
    19. pol.x = pul.x;
    20. pol.y = pul.y+myDrawRect.size.height-dyu-dyo;
    21. por.x = pur.x;
    22. por.y = pol.y;
    23. drawPath = [NSBezierPath bezierPath];
    24. [drawPath moveToPoint: pur];
    25. [drawPath lineToPoint: pul];
    26. [drawPath moveToPoint: NSMakePoint(pul.x, pul.y-4)];
    27. [drawPath lineToPoint: pol];
    28. [drawPath lineToPoint: por];
    29. [drawPath lineToPoint: pur];
    30. [drawPath lineToPoint: NSMakePoint(pur.x, pur.y-4)];
    31. [drawPath setLineWidth:1.0];
    32. }
    33. return self;
    34. }
    35. - (void)dealloc
    36. {
    37. [super dealloc];
    38. }
    39. - (void)drawRect:(NSRect)dirtyRect
    40. {
    41. // Drawing code here.
    42. [[NSColor controlHighlightColor] set];
    43. [NSBezierPath fillRect:myDrawRect];
    44. [[NSColor blackColor] set];
    45. // Set the default line cap style
    46. [NSBezierPath setDefaultLineCapStyle:NSButtLineCapStyle];
    47. [drawPath stroke];
    48. NSString *startString = @"00:00:00";
    49. NSString *endString = @"XX:XX:XX";
    50. NSPoint startPoint = NSMakePoint(pul.x-27,pul.y-18);
    51. NSPoint endPoint = NSMakePoint(pur.x-27,pur.y-18);
    52. NSMutableDictionary *textAttrib = [[NSMutableDictionary alloc] init];
    53. [textAttrib setObject:[NSFont fontWithName:@"Menlo" size:11] forKey:NSFontAttributeName];
    54. [textAttrib setObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName];
    55. [startString drawAtPoint:startPoint withAttributes:textAttrib];
    56. [endString drawAtPoint:endPoint withAttributes:textAttrib];
    57. if (i == 100)
    58. [[NSColor redColor] set]; else [[NSColor blackColor] set];
    59. // Set the line width for a single NSBezierPath object.
    60. NSBezierPath* thePath = [NSBezierPath bezierPath];
    61. [thePath moveToPoint:NSMakePoint(pul.x, 100.0)];
    62. [thePath lineToPoint:NSMakePoint(pur.x, 130.0)];
    63. [thePath stroke];
    64. }
    65. @end
    Alles anzeigen


    Hier meine Delegate.h:

    C-Quellcode

    1. #import <Cocoa/Cocoa.h>
    2. #include "MyView.h"
    3. @interface DummyAppDelegate : NSObject <NSApplicationDelegate> {
    4. @private
    5. IBOutlet MyView *myProfilView;
    6. }
    7. - (IBAction)myButton:(id)sender;
    8. @property (assign) IBOutlet NSWindow *window;
    9. @end
    Alles anzeigen


    Und hier noch der Button aus der .m Datei:

    Quellcode

    1. - (IBAction)BlaBla:(id)sender {
    2. [myProfilView setI: 100];
    3. [myProfilView display];
    4. }
  • Du solltest erst einmal die Speicherverwaltung lernen.

    drawPath ist keine retain Property sondern nur ein iVar. Das ist eigentlich schon der erste grtoße Fehler. Dann erstellst Du drawPath mit dem Conveniance Allocator. Das ist dann der fatale Fehler. Du wirst gar nicht Owner des Objectes und wenn du es denn würdest, dann würdest Du die Ownershipo nicht wieder abgeben und ein Speicherleak erzeugen. So aber ist drawPath nach Beenden der Init Methode wieder ohne Owner und wird freigegeben. Das es vorher mal funktioniert hat ist totaler Zufall.

    Also erstmal ran an die Grundlagen

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Wo und wie gebe ich dann aber drawPath wieder frei?
    Macht man das so?
    MyView.m:

    Quellcode

    1. - (void)dealloc
    2. {
    3. [drawPath release];
    4. [super dealloc];
    5. }


    Ach ja, display funktioniert auch! Was sollte man verwenden? display oder setNeedsDisplay? Und warum?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von LarsKrachen ()

  • LarsKrachen schrieb:

    In InitWithFrame lege ich einige Pfade (NSBezierPath) an. Hier wird ein Koordinatensystem für die spätere Ausgabe als Pfad hinterlegt.
    In drawRect wird dann nur noch gezeichnet. Später sollen weitere Datenobjekte (Polygone), die über die Setter der Klaase hinzugefügt werden, gezeichnet werden.

    Schön, dass es jetzt funktioniert ... aber ich verstehe nicht, warum: Nach meinem Verständnis nutzen Views, die im Interface Builder instanziert werden, zwar die Methode initWithCoder:, nicht aber initWithFrame. Wie also werden die von Dir in initWithFrame: initalisierten Objekte gesetzt? Oder hast Du diesen Code komplett in's drawRect: geschoben ... ?

    Leicht verwirrt, Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.