Rechteck zeichnen

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

  • Rechteck zeichnen

    Hallo, ich habe ein Problem, mit CGContext ein Rechteck zu zeichnen. Was mache ich falsch? Hier die Klasse von meinem View:

    Quellcode

    1. - (void)drawRect:(NSRect)dirtyRect {
    2. [[NSColor whiteColor] set];
    3. NSRectFill(dirtyRect);
    4. NSGraphicsContext *currentNSGraphicsContext = [NSGraphicsContext currentContext];
    5. CGContextRef currentCGContextRef = (CGContextRef) [currentNSGraphicsContext graphicsPort];
    6. CGContextSetRGBStrokeColor(currentCGContextRef, 1, 1, 1, 1);
    7. CGContextSetRGBFillColor(currentCGContextRef, 0.1, 0.2, 0.3, 0.4);
    8. CGContextSetLineWidth(currentCGContextRef, 5);
    9. CGContextStrokeRect(currentCGContextRef, CGRectMake(10, 10, 100, 100));
    10. }
    Alles anzeigen
  • Tja, gleich noch ein Problem. Ich möchte ein Rechteck auf Knopfdruck zeichnen. Hier mein Code:

    Quellcode

    1. #import "ViewController.h"
    2. @implementation ViewController
    3. @synthesize legends;
    4. @synthesize myView;
    5. - (id)initWithFrame:(NSRect)frame {
    6. self = [super initWithFrame:frame];
    7. if (self) {
    8. // Initialization code here.
    9. }
    10. legends = [[NSMutableArray alloc] init];
    11. return self;
    12. }
    13. - (void)dealloc {
    14. [super dealloc];
    15. }
    16. - (void)drawRect:(NSRect)dirtyRect {
    17. [[NSColor whiteColor] set];
    18. NSRectFill(dirtyRect);
    19. NSUInteger numberOfLegends = [legends count];
    20. NSGraphicsContext *currentNSGraphicsContext = [NSGraphicsContext currentContext];
    21. CGContextRef currentCGContextRef = (CGContextRef)[currentNSGraphicsContext graphicsPort];
    22. CGContextSetRGBStrokeColor(currentCGContextRef, 0, 0, 0, 0.5);
    23. CGContextSetRGBFillColor(currentCGContextRef, 0.1, 0.2, 0.3, 0.4);
    24. CGContextSetLineWidth(currentCGContextRef, 5);
    25. CGContextSetLineCap(currentCGContextRef, kCGLineCapRound);
    26. NSLog(@"numberOfLegends: %lu", numberOfLegends);
    27. // CGContextStrokeRect(currentCGContextRef, CGRectMake(10, 10, 100, 100));
    28. NSUInteger i;
    29. for (i = 0; i < numberOfLegends; i++) {
    30. Legend *actualLegend = [legends objectAtIndex:i];
    31. CGContextStrokeRect(currentCGContextRef, CGRectMake(actualLegend.newLegend.origin.x, actualLegend.newLegend.origin.y, actualLegend.newLegend.size.height, actualLegend.newLegend.size.width));
    32. }
    33. }
    34. - (IBAction)doAddLegend:(id)sender {
    35. Legend *legend = [[Legend alloc] initWithLegend];
    36. [legends addObject:legend];
    37. // NSUInteger numberOfLegends = [legends count];
    38. // NSLog(@"numberOfLegends: %lu", numberOfLegends);
    39. [myView setNeedsDisplay:YES];
    40. }
    41. @end
    Alles anzeigen


    Problem: In der Action wird numberOfLegends pro Knopfdruck auch um eins erhöht. In der drawRect-Methode allerdings nie! Warum ist das so? Und wie kann ich es ändern? Die Klasse Legend besteht nur aus einem NSRect.
  • Ist das denn wichtig? Im Zweifel würden alle Rechtecke übereinandergezeichnet ohne dass man es sehen würde... Das macht aber erstmal nichts, da überhaupt nichts gezeichnet wird. Und das liegt daran, dass kein numberOfLegends in der drawRect Methode leer ist...
  • Also meine Klasse Legend hat die Methode:

    Quellcode

    1. - (id)initWithLegend {
    2. self = [super init];
    3. if (self) {
    4. // Initialization code here.
    5. }
    6. newLegend.origin.x = 10;
    7. newLegend.origin.y = 10;
    8. newLegend.size.width = 100;
    9. newLegend.size.height = 50;
    10. return self;
    11. }
    Alles anzeigen


    Also wird immer ein Rechteck mit diesen Koordinaten erzeugt. Ich habe gerade folgendes ausprobiert. Eine neue Methode, wenn man die Maustaste im View drückt, die dasselbe wie die andere macht, wenn man also den Button drückt:

    Quellcode

    1. - (void)mouseDown:(NSEvent *)theEvent {
    2. Legend *legend = [[Legend alloc] initWithLegend];
    3. [legends addObject:legend];
    4. [myView setNeedsDisplay:YES];
    5. }


    Drücke ich nun die Maustaste und danach den Button, wird das Rechteck gezeichnet... Ich habe das Projekt mal angehängt.
  • Erstmal generell, Deine init-Methoden:
    Nur eine von denen ruft nach super auf, alle anderen gehen über die eine, den designierten Initialisiere.
    Und natürlich willst Du Deine eine Eigenschaft mit initialisieren.
    <ein Vorschlag desw.:

    Quellcode

    1. - (id)init {
    2. return [self initWithLegend: NSMakeRect(10.0, 10.0, 100.0, 40.0)];
    3. }
    4. - (id)initWithLegend: (NSRect) newRect{
    5. self = [super init];
    6. if (self) {
    7. // Initialization code here.
    8. self.newLegend = newRect;
    9. }
    10. return self;
    11. }
    Alles anzeigen
    I would be embarrassed if they did not spy on me.
  • Also bei mir zeichnet was, aber nicht immer sofort.
    Das ist alles irgendwie atypisch, ich würde NSColor und NSBezierPath nehmen, aber egal.
    Dein NSLog ist falsch, statt %lu solltest Du einfach %d nehmen:

    Quellcode

    1. NSLog(@"doAddLegend numberOfself.legends: %d", [self.legends count]);


    Dein MutableArray würde ich als property mit 'retain' versehen.
    Dann lassen sich die Speicherregeln besser beachten.

    Warum es nicht immer klappt, weiss ich auch.
    Ich vermute den Context.

    Edit:
    Nein:

    Quellcode

    1. @interface ViewController : NSView {
    2. @private
    3. NSMutableArray *legends;
    4. ViewController *myView;
    5. }
    6. @property (assign) NSMutableArray *legends;
    7. @property (assign) IBOutlet ViewController *myView;
    8. - (IBAction)doAddLegend:(id)sender;
    9. @end
    Alles anzeigen

    Du benennst Deine Zeichenfläche als "ViewController".
    Du kannst Namen wählen, wie Du lustig bist, solange er nicht vergeben sit, aber das ist an der Kante, weil es grundlegende konzeoptionelle zwischen View und Controller gibt.
    Schau mal nach "MVC".

    Dann hast Du selbst eine Instanz Deine Klasse selbst in Deiner Klasse "ViewController" eingebaut.
    Dadurch funktioniert "-mouseDown" nicht, und 'setNeedsDisplay" wird nicht aufgerufen, bzw. nicht auf die richtige Instanz.
    Wenn Du zwischen Mausklick und Toolbar wechselst, dann wird auch gezeichnet.
    I would be embarrassed if they did not spy on me.

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

  • Hallo,
    also ich habe jetzt die Klasse umbenannt in MyViewController. Außerdem habe ich anstatt [legends ...] [self.legends ...]. Frage hier: Warum muss ich ein self davor machen? Ohne funktioniert es bei mir genauso wie mit.

    Weiter habe ich die Initialisierung so wie beschrieben geändert und natürlich die init-Methode beim alloc verwendet. retain habe ich für mein MutableArray gesetzt. Den View als Outlet habe ich gelassen, da in der Methode doAddLegend mit [self setNeedsDisplay:YES] im Gegensatz zu [myView selfNeedsDisplay:YES] nicht neu gezeichnet wird.

    Allerdings: Das Problem bleibt bei mir bestehen. Der NSLog zeigt mir beim Aufrufen der Methode doAddLegend, dass Objekte hinzugefügt werden. Aber wenn danach neu gezeichnet wird, wird angezeigt, dass das Array leer ist... Habe ich jetzt noch etwas falsch gemacht?
  • DaPhil schrieb:

    Hallo,
    also ich habe jetzt die Klasse umbenannt in MyViewController.

    Nein, ich meinte, dass das kein 'Controller' ist, als Unterklasse von NSView.
    Also einfach: "MyView", oder genauer spezifiziert, was darin gezeihnet wird, also bei einem GPS-Programm vielleicht "SateliteView" und "CompassView".

    DaPhil schrieb:

    Außerdem habe ich anstatt [legends ...] [self.legends ...]. Frage hier: Warum muss ich ein self davor machen? Ohne funktioniert es bei mir genauso wie mit.

    NEinmal greifst Du auf die Variable direkt zu, was man versuchen sollte zu vermeiden, einmal über den getter/setter, die Methoden.
    Du solltest Dir Grundlagen aneignen.

    DaPhil schrieb:

    Weiter habe ich die Initialisierung so wie beschrieben geändert und natürlich die init-Methode beim alloc verwendet. retain habe ich für mein MutableArray gesetzt. Den View als Outlet habe ich gelassen, da in der Methode doAddLegend mit [self setNeedsDisplay:YES] im Gegensatz zu [myView selfNeedsDisplay:YES] nicht neu gezeichnet wird.

    Du Hast ein Durcheinander dort, weil Du 2 Instanzen Deines "NSView", dass auch noch Controller heisst, erzeugst.
    Das musst Du aufdröseln.

    DaPhil schrieb:

    Allerdings: Das Problem bleibt bei mir bestehen. Der NSLog zeigt mir beim Aufrufen der Methode doAddLegend, dass Objekte hinzugefügt werden. Aber wenn danach neu gezeichnet wird, wird angezeigt, dass das Array leer ist... Habe ich jetzt noch etwas falsch gemacht?


    Auch dass eine Folge der zwei Instanzen: Welche soll neu gezeichnet werden.
    I would be embarrassed if they did not spy on me.
  • gritsch schrieb:

    aufzupassen ist jedoch dass man manchmal von einem getter ein immutable objekt bekommst und kein mutable! hat eben vor-und nachteile!

    Quellcode

    1. @interface ViewController : NSView {
    2. @private
    3. NSMutableArray *legends;
    4. ViewController *myView;
    5. }
    6. @property (assign) NSMutableArray *legends;
    7. @property (assign) IBOutlet ViewController *myView;
    8. - (IBAction)doAddLegend:(id)sender;
    9. @end
    Alles anzeigen



    Im Moment sieht das so aus…
    I would be embarrassed if they did not spy on me.
  • Ok, das mit dem Namen und self habe ich verstanden. Du hast aber schon richtig bemerkt, ich bin ein Anfänger und probiere gerade ein bisschen was aus. Deshalb die Frage/Bitte: Kannst du mir etwas genauer erklären, was du mit "aufdröseln" meinst? Das Outlet muss weg, richtig? Aber wie bekomme ich dann den View dazu, sich neu zu zeichnen?

    Edit: Bei der Maus klappts schon! Aber derselbe Code mit der Action klappt nicht..
  • DaPhil schrieb:

    Ok, das mit dem Namen und self habe ich verstanden. Du hast aber schon richtig bemerkt, ich bin ein Anfänger und probiere gerade ein bisschen was aus. Deshalb die Frage/Bitte: Kannst du mir etwas genauer erklären, was du mit "aufdröseln" meinst? Das Outlet muss weg, richtig? Aber wie bekomme ich dann den View dazu, sich neu zu zeichnen?

    Edit: Bei der Maus klappts schon! Aber derselbe Code mit der Action klappt nicht..


    Dann fehlt wahrscheinlich eine Verknüpfung im IB.
    I would be embarrassed if they did not spy on me.