繪圖

在這裡使用 GNUstep 的繪圖功能來顯示時間.

圖形 12.21. Custom view with analog clock

Custom view with analog clock

概念上很簡單, 就是在 TimeView 中再加入個自訂元件, ClockView, 即上圖中黃色的時鐘. 當 TimeView 的時間更新時, 也更新 ClockView.

ClockView.h:

#import <AppKit/AppKit.h>
#include <math.h>

@interface ClockView : NSView
{
   NSPoint posHour, posMinute;
}

- (void) setDate: (NSCalendarDate *) aDate;
@end

ClockView.m:

#import "ClockView.h"

@implementation ClockView
- (id) init
{
   self = [super init];
   posHour = NSMakePoint(0,0);
   posMinute = NSMakePoint(0,0);
   return self;
}

- (void) drawRect: (NSRect) frame
{
   NSPoint origin = NSMakePoint(frame.size.width/2, frame.size.height/2);

   NSBezierPath *bp = [NSBezierPath bezierPathWithRect: [self bounds]];
   [[NSColor yellowColor] set];
   [BP fill];

   BP = [NSBezierPath bezierPathWithRect: NSMakeRect(1, 1,
                                                     frame.size.width-2,
                                                     frame.size.height-2)];
   [[NSColor blackColor] set];
   [BP stroke];

   BP = [NSBezierPath bezierPath];
   [BP setLineWidth: 3];
   [BP moveToPoint: origin];
   [BP relativeLineToPoint: posHour];
   [BP stroke];

   [BP setLineWidth: 1];
   [BP moveToPoint: origin];
   [BP relativeLineToPoint: posMinute];
   [BP stroke];
}

- (void) setDate: (NSCalendarDate *) date;
{
   int hour = [date hourOfDay];
   int minute = [date minuteOfHour];
   float hour_x = 40*sin((M_PI*hour/6)+(M_PI*minute/360));
   float hour_y = 40*cos((M_PI*hour/6)+(M_PI*minute/360));
   float minute_x = 60*sin(M_PI*minute/30);
   float minute_y = 60*COs(M_PI*minute/30);

   posHour = NSMakePoint(hour_x, hour_y);
   posMinute = NSMakePoint(minute_x, minute_y);
   [self setNeedsDisplay: YES];
}

@end

ClockView 繼承自 NSView. 最重要的是 -drawRect:. 每次更新視窗時, 就會從 Superview 一路往下呼叫 -drawRect:. 因此所有要更新的部份都在這裡. NSBezierPath 是 GNUstep 中繪圖的元件. 首先先決定路徑, 設定顏色, 最後會是繪圖. 這裡有些相關的文章 (英文) 可以參考: Introduction to Cocoa Graphics, Part I, Part II.

製做好 ClockView 後, 記得在 TimeView 加入 ClockView, 使其成為 TimeView 的 subview. 並在 TimeView 便新時間時呼叫 ClockView 的 -setDate:, 以更新 ClockView 的內容. 在 ClockView 中, [self setNeedsDisplay: YES]; 會通知 GNUstep 要更新 ClockView. 這時 -drawRect: 便會被呼叫. 這些修改很簡單, 可以自行完成.