我将这个“墙 'o 代码”作为(大部分)完整的方法在自定义 NSView 中进行区域选择,并能够随后扩展/移动“行进的蚂蚁”矩形。
希望有人在那里发现它有用。
对“introThumbRect”的初始调用让球滚动起来。矩形的边可以随着鼠标光标的适当变化而扩大。选择矩形也可以移动。初始/生成的矩形位于视图的“thumbRect”属性中(相对于“fullImage”坐标系)。“cropPt”值是显示图像“fullImage”的左上角;出于此处的目的,假设它是 (0,0)。
我遇到的一个问题是,一旦发生鼠标拖动(即展开边或移动矩形),我正在使用鼠标光标将其保持在原始拖动状态。它想要恢复为箭头光标,而它应该将自己保持为例如张开手光标。我相信这是由于重新计算跟踪区域而发生的,但这样的问题实际上是不可能调试的,因为 XCode 不会“跟踪”光标状态。
如果有人可以帮助修复那个小错误,那就太好了。
#import <Cocoa/Cocoa.h>
@interface ThumbNailView : NSView
@property (nonatomic, strong) NSImage *fullImage;
@property (nonatomic) CGPoint cropPt;
@property (nonatomic) CGRect thumbRect;
- (void)introThumbRect;
@end
@implementation ThumbNailView
{
NSMutableArray *trackingAreas;
NSCursor *dragCursor;
NSTimer *antTimer;
NSInteger antPhase;
NSString *dragMode;
CGRect origThumbRect;
CGPoint thumbPt;
CGPoint mouseLoc;
BOOL thumbVisible;
BOOL updatedTracking;
BOOL amDragging;
}
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self)
[self setThumbRect:CGRectZero];
return self;
}
-(BOOL) isFlipped
{
return YES;
}
- (void)setupTrackingOnRect:(CGRect)r
{
CGRect trackRects[5];
int d=5;
// these are tracking rectangles for the interior + 4 sides of the rectangle
trackRects[0] = CGRectMake(r.origin.x+d,r.origin.y+d,
r.size.width-d*2,r.size.height-d*2); // main interior
trackRects[1] = CGRectMake(r.origin.x-d,r.origin.y+d,
d*2,r.size.height-d*2); // left side
trackRects[2] = CGRectMake(r.origin.x+r.size.width-d,r.origin.y+d,
d*2,r.size.height-d*2); // right side
trackRects[3] = CGRectMake(r.origin.x+d,r.origin.y-d,
r.size.width-d*2,d*2); // top side
trackRects[4] = CGRectMake(r.origin.x+d,r.origin.y+r.size.height-d,
r.size.width-d*2,d*2); // bottom inside
NSMutableArray *dicts = [[NSMutableArray alloc] init];
[dicts addObject:[[NSDictionary alloc] initWithObjectsAndKeys:
NSStringFromRect(CGRectMake(1,1,0,0)),@"moveMode",
[NSCursor openHandCursor], @"cursor",nil]];
[dicts addObject:[[NSDictionary alloc] initWithObjectsAndKeys:
NSStringFromRect(CGRectMake(1,0,-1,0)),@"moveMode",
[NSCursor resizeLeftRightCursor],@"cursor",nil]];
[dicts addObject:[[NSDictionary alloc] initWithObjectsAndKeys:
NSStringFromRect(CGRectMake(0,0,1,0)),@"moveMode",
[NSCursor resizeLeftRightCursor],@"cursor",nil]];
[dicts addObject:[[NSDictionary alloc] initWithObjectsAndKeys:
NSStringFromRect(CGRectMake(0,1,0,-1)),@"moveMode",
[NSCursor resizeUpDownCursor], @"cursor",nil]];
[dicts addObject:[[NSDictionary alloc] initWithObjectsAndKeys:
NSStringFromRect(CGRectMake(0,0,0,1)),@"moveMode",
[NSCursor resizeUpDownCursor], @"cursor",nil]];
NSTrackingAreaOptions myOptions = NSTrackingMouseEnteredAndExited |
NSTrackingMouseMoved;
NSMutableArray *tracks = [[NSMutableArray alloc] init];
for (int i=0; i<5; i++) {
NSDictionary *dict = [dicts objectAtIndex:i];
[tracks addObject:[[NSTrackingArea alloc] initWithRect:trackRects[i]
options:myOptions | NSTrackingActiveInKeyWindow
owner:self
userInfo:dict]];
[self addTrackingArea:[tracks objectAtIndex:i]];
}
trackingAreas=tracks;
}
- (void)updateTrackingAreas
{
if (dragCursor)
[dragCursor set];
[super updateTrackingAreas];
if (dragCursor)
[dragCursor set];
for (NSTrackingArea *t in [self trackingAreas])
[self removeTrackingArea:t];
trackingAreas=nil;
if (thumbVisible) {
CGRect tRect = CGRectOffset([self thumbRect],
thumbPt.x-[self cropPt].x,
thumbPt.y-[self cropPt].y);
[self setupTrackingOnRect:tRect];
}
}
- (void)mouseEntered:(NSEvent *)theEvent
{
if (amDragging)
return;
NSDictionary *userDict = [theEvent userData];
if (userDict) {
NSCursor *newCursor = [userDict objectForKey:@"cursor"];
if (newCursor) {
[newCursor set];
dragCursor=newCursor;
}
NSString *newMode = [userDict objectForKey:@"moveMode"];
if (newMode)
dragMode=newMode;
}
}
- (void)mouseExited:(NSEvent *)theEvent
{
if (!amDragging) {
[[NSCursor arrowCursor] set];
dragMode=nil;
dragCursor=nil;
}
}
- (void)mouseDragged:(NSEvent *)theEvent
{
if (dragMode) {
amDragging=YES;
if (dragCursor)
[dragCursor set];
CGPoint newLoc = [NSEvent mouseLocation];
NSInteger deltaX = mouseLoc.x - newLoc.x;
NSInteger deltaY = mouseLoc.y - newLoc.y;
CGRect moveMode = NSRectFromString(dragMode);
CGRect trect = CGRectOffset(origThumbRect,-moveMode.origin.x*deltaX,moveMode.origin.y*deltaY);
trect.size.width -= moveMode.size.width*deltaX;
trect.size.height += moveMode.size.height*deltaY;
[self setThumbRect:trect];
updatedTracking=NO;
[self setNeedsDisplay:YES];
}
}
- (void)mouseMoved:(NSEvent *)theEvent
{
if (dragCursor)
[dragCursor set];
}
- (void)mouseDown:(NSEvent *)theEvent
{
mouseLoc=[NSEvent mouseLocation];
origThumbRect = [self thumbRect];
}
- (void)mouseUp:(NSEvent *)theEvent
{
amDragging=NO;
dragCursor=nil;
[self setNeedsDisplay:YES];
}
- (void)introThumbRect
{
NSInteger h = [self frame].size.height;
if (!h)
return;
CGRect thumbRect = CGRectMake(0,0,140.0*h/64.0,h);
thumbPt = [self cropPt];
[self setThumbRect:thumbRect];
[self setNeedsDisplay:YES];
}
- (void) antMarch:(NSTimer *)timer
{
antPhase = (antPhase+1)%7;
[self setNeedsDisplay:YES];
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
[[NSColor greenColor] set];
[NSBezierPath fillRect:dirtyRect];
CGRect cropRect = CGRectMake([self cropPt].x,
[self cropPt].y,
[self frame].size.width,
[self frame].size.height);
CGRect myRect = CGRectMake(0,0,cropRect.size.width,cropRect.size.height);
[[self fullImage] drawInRect:myRect
fromRect:cropRect
operation:NSCompositeCopy
fraction:1.0
respectFlipped:YES
hints:nil];
if (CGRectEqualToRect(CGRectZero,[self thumbRect]))
return;
CGRect tRect = CGRectOffset([self thumbRect],
thumbPt.x-[self cropPt].x,
thumbPt.y-[self cropPt].y);
CGRect iRect = CGRectIntersection(myRect,tRect);
if (CGRectIsNull(iRect)) {
if (thumbVisible) {
thumbVisible=NO;
[self updateTrackingAreas];
}
if (antTimer) {
[antTimer invalidate];
antTimer=nil;
}
return;
}
thumbVisible=YES;
[self drawThumbBox];
if (!antTimer) {
antTimer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:@selector(antMarch:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:antTimer forMode: NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:antTimer forMode: NSEventTrackingRunLoopMode];
}
//if (![self inDrag])
if (dragCursor)
[dragCursor set];
if (!updatedTracking) {
updatedTracking=YES;
[self updateTrackingAreas];
}
}
- (void)drawThumbBox
{
NSInteger deltaX = thumbPt.x-[self cropPt].x;
NSInteger deltaY = thumbPt.y-[self cropPt].y;
CGRect tRect = CGRectOffset([self thumbRect],deltaX,deltaY);
NSCompositingOperation curComp = [[NSGraphicsContext currentContext] compositingOperation];
[[NSGraphicsContext currentContext] setCompositingOperation:NSCompositeXOR];
// draw marching ants
[[NSColor blackColor] set];
NSBezierPath *selectionPath = [NSBezierPath bezierPathWithRect:tRect];
CGFloat dashArray[2] = {5.0, 2.0};
[selectionPath setLineDash:dashArray
count:sizeof(dashArray)/sizeof(CGFloat)
phase:antPhase];
[selectionPath stroke];
[[NSGraphicsContext currentContext] setCompositingOperation:curComp];
}
@end