Cocoa 应用中根本没有调用 drawRect()

drawRect() is not called at all in Cocoa app

我是编程 OS X Cocoa 应用程序的新手。所以请同情。我想让一个应用程序变得简单,但我已经阻止了自己在应用程序中绘制图像。

此代码应绘制多个图像并在调整大小时或最大化 window 应用程序时更改排列。

#include <Cocoa/Cocoa.h>

#ifndef NSWindowStyleMaskTitled
#define NSWindowStyleMaskTitled NSTitledWindowMask
#define NSWindowStyleMaskClosable NSClosableWindowMask
#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
#define NSWindowStyleMaskResizable NSResizableWindowMask
#define NSEventMaskAny NSAnyEventMask
#endif

@interface Window : NSWindow {
    NSTimer* mTimer;
}
- (instancetype)init;
- (BOOL) acceptsFirstResponder;
- (BOOL) acceptsFirstMouse: (NSEvent*) pEvent;
- (void) viewDidMoveToWindow;
- (void) drawRect: (NSRect) rect;
- (void) onTimer: (NSTimer*) pTimer;
- (void) getMouseXY: (NSEvent*) pEvent x: (int*) pX y: (int*) pY;
- (void) mouseDown:(NSEvent*)event;
- (void) mouseUp: (NSEvent*) event;
- (void) mouseDragged: (NSEvent*) event;
- (void) rightMouseDown: (NSEvent*) event;
- (void) rightMouseUp: (NSEvent*) event;
- (NSDragOperation) draggingEntered:(id <NSDraggingInfo>)sender;
- (BOOL) performDragOperation:(id <NSDraggingInfo>)sender;
- (void) windowDidResize:(NSNotification*)notification;
- (void) windowDidMiniaturize:(NSNotification*)sender;
- (void) windowDidDeMiniaturize:(NSNotification*)sender;
- (BOOL) windowShouldClose:(id)sender;
@end

@implementation Window
- (instancetype)init {
    
    mTimer = 0;
    double sec = 1.0 / 24;
    mTimer = [NSTimer timerWithTimeInterval:sec target:self selector:@selector(onTimer:) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer: mTimer forMode: (NSString*) kCFRunLoopCommonModes];
    [self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:self];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:self];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidDeMiniaturize:) name:NSWindowDidDeminiaturizeNotification object:self];

    
    [super initWithContentRect:NSMakeRect(0, 0, 500, 300) styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable backing:NSBackingStoreBuffered defer:NO];
  [self setTitle:@"Hello world"];
  [self center];
    
    [self setOpaque:NO];
    [self setHasShadow:YES];
    //[self setBackgroundColor:[NSColor clearColor]];
    [self setBackgroundColor:[NSColor grayColor]];
    
  [self setIsVisible:YES];
  return self;
}
- (BOOL) acceptsFirstResponder {
    return YES;
}
- (BOOL) acceptsFirstMouse: (NSEvent*) pEvent {
    return YES;
}
- (void) viewDidMoveToWindow {
    NSWindow* pWindow = [self window];
    if (pWindow) {
        [pWindow makeFirstResponder: self];
        [pWindow setAcceptsMouseMovedEvents: YES];
    }
}
- (void) drawRect: (NSRect) rect {
    
    NSLog(@"drawRect %f, %f, %f", rect.origin.x, rect.origin.y, rect.size.width);
}
- (void) onTimer: (NSTimer*) pTimer {
    NSRect r;
    if (pTimer == mTimer) {
        //NSLog(@"mTimer");

    }
}
- (void) getMouseXY: (NSEvent*) pEvent x: (int*) pX y: (int*) pY {
    NSPoint pt = [pEvent locationInWindow];
    *pX = (int) pt.x;
    //*pY = mGraphics->Height() - (int) pt.y;
    *pY = 555 - (int) pt.y;
    NSLog(@"%f , %f", pt.x, pt.y);

}
- (void)mouseDown:(NSEvent*)event {
    NSLog(@"mouseDown called");
}
- (void) mouseUp: (NSEvent*) event {
    int x, y;
    [self getMouseXY:event x:&x y:&y];
}
- (void) mouseDragged: (NSEvent*) event {
    int x, y;
    [self getMouseXY:event x:&x y:&y];
}
- (void) rightMouseDown: (NSEvent*) event {
    int x, y;
    [self getMouseXY:event x:&x y:&y];
}
- (void) rightMouseUp: (NSEvent*) event {
    int x, y;
    [self getMouseXY:event x:&x y:&y];
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>) sender {
    NSPasteboard *pboard = [sender draggingPasteboard];
    return (([pboard.types containsObject:NSFilenamesPboardType]) ? NSDragOperationLink : NSDragOperationNone);
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>) sender {
    NSPasteboard *pboard = [sender draggingPasteboard];
    if ( [[pboard types] containsObject:NSFilenamesPboardType] ) {
        //NSPoint pt = [self convertPoint:[sender draggingLocation] fromView:nil];
        for (NSString *path in [pboard propertyListForType:NSFilenamesPboardType]) {
            const char* tmp=[path UTF8String];
            NSLog(@"%@", path);
            //if (mGraphics)  {
                //mGraphics->OnMouseDrop(pt.x, mGraphics->Height() - pt.y, (char*)tmp);
                //break;
            //}
        }
    }
    return YES;
}
- (void)windowDidResize:(NSNotification*)notification {
    //NSLog(@"Resize");
}
- (void)windowDidMiniaturize:(NSNotification*)notification {
    NSLog(@"Minimize");
}
- (void)windowDidDeMiniaturize:(NSNotification*)notification {
    NSLog(@"DeMinimize");
}
- (BOOL)windowShouldClose:(id)sender {
  [NSApp terminate:sender];
  return YES;
}
@end

int main(int argc, char* argv[]) {
  [NSApplication sharedApplication];
  [[[[Window alloc] init] autorelease] makeMainWindow];
  [NSApp run];
}

但是根本没有调用drawRect(),这是什么问题?

这个过程是不是应该像Windows一样,在有需要重绘的脏区时调用?

So, how do I complete my code with NSView?

代替使用您的示例,我建议您考虑以下内容。这是另一种以编程方式创建 Cocoa 应用程序的方法,并演示了在自定义 NSView 中使用 -drawRect()。请注意,window 可调整大小,类似于您发布的内容。要在Xcode中运行先创建一个objc工程,然后删除给你提供的AppDelegate,删除原代码后将下面的内容粘贴到main.m中:

#import <Cocoa/Cocoa.h>

@interface CustomView : NSView
//methods automatically called
@end

@implementation CustomView

- (id)initWithFrame:(NSRect)frameRect {
 if ((self = [super initWithFrame:frameRect]) != nil) {
  // Add initialization code here
 }
 return self;
}

- (void)drawRect:(NSRect)rect {
// **** Background **** //
[[NSColor orangeColor] set];
[NSBezierPath fillRect:rect];

NSBezierPath *path = [NSBezierPath bezierPathWithOvalInRect:NSInsetRect([self bounds], 30,30)];
[[NSColor redColor] set];
[path fill];
[[NSColor whiteColor] set];
[path setLineWidth:1.0];
[path stroke];
}

//  Use this if you want 0,0 (origin) to be top, left //
//  Otherwise origin will be at bottom, left (Unflipped) //
-(BOOL)isFlipped {
 return YES;
}
@end

@interface AppDelegate : NSObject <NSApplicationDelegate> {
  NSWindow *window;
}
- (void) myBtnAction: (id)sender;
- (void) buildMenu;
- (void) buildWnd;
@end

@implementation AppDelegate

- (void) myBtnAction: (id)sender {
 NSBeep();
}

- (void) buildMenu {
NSMenu *menubar = [NSMenu new];
NSMenuItem *appMenuItem = [NSMenuItem new];
[menubar addItem:appMenuItem];
[NSApp setMainMenu:menubar];
NSMenu *appMenu = [NSMenu new];
NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:@"Quit"
        action:@selector(terminate:) keyEquivalent:@"q"];
[appMenu addItem:quitMenuItem];
[appMenuItem setSubmenu:appMenu];
}

- (void) buildWnd {
#define _wndW 500
#define _wndH 450

window = [[NSWindow alloc] initWithContentRect: NSMakeRect( 0, 0, _wndW, _wndH )styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable backing: NSBackingStoreBuffered defer: NO];
[window center];
[window setTitle: @"Custom View"];
[window makeKeyAndOrderFront: nil];

// **** Create an instance of CustomView (NSView) **** //
CustomView *view = [[CustomView alloc]initWithFrame:NSMakeRect( 20, 80, _wndW - 40, _wndH - 100 )];
[view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
[[window contentView] addSubview:view];

// **** Button **** //
NSButton *myBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 30, 30, 95, 30 )];
[myBtn setBezelStyle:NSBezelStyleRounded ];
[myBtn setTitle: @"Beep"];
[myBtn setAction: @selector (myBtnAction:)];
[[window contentView] addSubview: myBtn];

// **** Quit btn **** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 50, 10, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular ];
[quitBtn setTitle: @"Q" ];
[quitBtn setAutoresizingMask: NSViewMinXMargin];
[quitBtn setAction:@selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}

- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildMenu];
[self buildWnd];
}

- (void) applicationDidFinishLaunching: (NSNotification *)notification {
}
@end

int main() {
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}