 |
 |
Best way to make a selection triangle
|
 |
|
 |
|
Fresh-Faced Recruit
Join Date: Jun 2000
Location: Oslo, Norway
Status:
Offline
|
|
I've just started using ProjectBuilder and trying to understand Cocoa. Just for the fun of it, I'm trying to make a program which duplicates the red eye removal feature of iPhoto.
I now have a workable program, but the way I've implemented the selection triangle is slow and jerky. I wonder if you have a better solution.
What I do now is that I register the point of the mouseDown event, and for each mouseDragged event I register the current position of the mouse and use a NSBezierPath to draw and outlined rectangle in the drawRect method.
iPhoto's selection rectangle is fluid compared to my implementation. So I guess Apple doesn't do it like I do. Do any of you have an idea of a better way to do this?
Here's an excerpt of my code, which is an subclass of NSImageView.
Code:
- (void)mouseDown: (NSEvent *)theEvent
{
hasBeenDragged = NO;
p1 = [theEvent locationInWindow];
p2 = p1;
p2Last = p1;
[self display];
}
- (void)mouseDragged: (NSEvent *)theEvent
{
hasBeenDragged = YES;
p2Last = p2;
p2 = [theEvent locationInWindow];
[self display];
}
- (void)drawRect: (NSRect)rectangle
{
// Have to call super or else
// my image won't be drawn to screen
[super drawRect:rectangle];
if (hasBeenDragged == YES) {
vp1 = [self convertPoint: p1 fromView:nil];
vp2 = [self convertPoint: p2 fromView:nil];
float x = (float)vp1.x;
float y = (float)vp1.y;
float width = (float)(vp2.x - vp1.x);
float height = (float)(vp2.y - vp1.y);
if (x > vp2.x)
x = vp2.x;
if (y > vp2.y)
y = vp2.y;
width = (width < 0 ) ? width * -1 : width;
height = (height < 0) ? height * -1 : height;
NSRect rec = NSMakeRect(x, y, width, height);
selectedArea = rec;
[[NSColor blackColor] set];
[NSBezierPath strokeRect:rec];
}
}
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status:
Offline
|
|
Since you're only drawing outlines (not filled shapes), you could speed things up a little by only drawing the image where the old box was and then drawing your new box.
You could get more optimization by caching the image contents under your box and then drawing 'em back in yourself - that'd save you the overhead of super drawing the NSImage, which ain't the speediest class around.
You might be able to pull an old-skewl mac trick where you use XOR mode to draw, but I think that only worked for B&W displays.
|
Geekspiff - generating spiffdiddlee software since before you began paying attention.
|
| |
|
|
|
 |
|
 |
|
Dedicated MacNNer
Join Date: Nov 2000
Status:
Offline
|
|
You might be able to pull an old-skewl mac trick where you use XOR mode to draw, but I think that only worked for B&W displays.
XOR style drawing is a pretty common technique. It's certainly not limited to B&W displays.
|
|
|
| |
|
|
|
 |
|
 |
|
Fresh-Faced Recruit
Join Date: Jun 2000
Location: Oslo, Norway
Status:
Offline
|
|
Originally posted by smeger:
Since you're only drawing outlines (not filled shapes), you could speed things up a little by only drawing the image where the old box was and then drawing your new box.
This is one of the things I really don't understand. I'm trying to call drawRect: explicitly, with only the coordinates of the box, but then nothing draws itself.
You could get more optimization by caching the image contents under your box and then drawing 'em back in yourself - that'd save you the overhead of super drawing the NSImage, which ain't the speediest class around.
You might be able to pull an old-skewl mac trick where you use XOR mode to draw, but I think that only worked for B&W displays.
Could you give me a quick description of where I should look in the Cocoa documentation to achieve such things? If you have example code that would certainly be best, but I'm not going to ask too much here... 
|
|
|
| |
|
|
|
 |
|
 |
|
Senior User
Join Date: Dec 2001
Status:
Offline
|
|
Originally posted by scotty:
This is one of the things I really don't understand. I'm trying to call drawRect: explicitly, with only the coordinates of the box, but then nothing draws itself.
drawRect: is the method you override. It is called by AppKit with the proper view focused and the proper state set. If you call it manually, you are basically drawing to a random spot. You want to call either setNeedsDisplay: YES (to have AppKit take care of it the next time through the run loop) or displayRect: (yourRect) (to have AppKit setup and call drawRect: immediately).
Originally posted by scotty:
Could you give me a quick description of where I should look in the Cocoa documentation to achieve such things? If you have example code that would certainly be best, but I'm not going to ask too much here...
Assuming you have the developer docs installed, the info you are looking for should be right here.
|
|
"Think Different. Like The Rest Of Us."
iBook G4/1.2GHz | 1.25GB | 60GB | Mac OS X 10.4.2
Athlon XP 2500+/1.83GHz | 1GB PC3200 | 120GB | Windows XP
|
| |
|
|
|
 |
|
 |
|
Clinically Insane
Join Date: Oct 2001
Location: San Diego, CA, USA
Status:
Offline
|
|
Originally posted by macmike42:
drawRect: is the method you override. It is called by AppKit with the proper view focused and the proper state set. If you call it manually, you are basically drawing to a random spot.
Except that obviously the right view will be focused when this method is called, since the class is calling it on itself in its drawRect: method.
Another thing about the problem at hand, though: Are you sure Apple uses an NSImageView for this? Because honestly, I almost never use NSImageView. It's so easy to get the basic functionality that I always just write a custom view to handle precisely what I want done.
|
|
Chuck
___
"Instead of either 'multi-talented' or 'multitalented' use 'bisexual'."
|
| |
|
|
|
 |
|
 |
|
Senior User
Join Date: Dec 2001
Status:
Offline
|
|
Originally posted by Chuckit:
Except that obviously the right view will be focused when this method is called, since the class is calling it on itself in its drawRect: method.
If this is what you think, fine, but please don't inflict your ignorance of Cocoa drawing on others. You override drawRect:, but you DO NOT call it. You always call one of the display* methods, or setNeedsDisplay: if the drawing can deferred until later.
Originally posted by Chuckit:
Another thing about the problem at hand, though: Are you sure Apple uses an NSImageView for this? Because honestly, I almost never use NSImageView. It's so easy to get the basic functionality that I always just write a custom view to handle precisely what I want done.
I never said anything about NSImageViews. I directed scotty to the 'constants' section of the documentation for the NSImage class. This sections lists the various compositing modes available to Cocoa. I haven't done much with them, but it clearly states that they are defined in NSGraphics.h, not NSImage.h, so I would imagine there is a way to use them on, say, an NSBitmapImageRep, and avoid the overhead of using an NSImage.
|
|
"Think Different. Like The Rest Of Us."
iBook G4/1.2GHz | 1.25GB | 60GB | Mac OS X 10.4.2
Athlon XP 2500+/1.83GHz | 1GB PC3200 | 120GB | Windows XP
|
| |
|
|
|
 |
|
 |
|
Clinically Insane
Join Date: Oct 2001
Location: San Diego, CA, USA
Status:
Offline
|
|
Originally posted by macmike42:
If this is what you think, fine, but please don't inflict your ignorance of Cocoa drawing on others.
Sir, it's not my fault if you have difficulty getting laid. Don't take it out on me. I don't care how 1337 you may think you are; if Andrew Welch and Rick Roe can be polite, you can too.
Actually, though, I just misunderstood where he meant he was calling drawRect:. I thought he was talking about in the code he posted here--with [super drawRect:rectangle]--which is, of course, correct.
To add a little bit to your actually helpful advice, though, setNeedsDisplayInRect:(NSRect)rectangle is better for optimized drawing than setNeedsDisplay:YES.
I never said anything about NSImageViews.
I wasn't talking to you there. I mentioned right beforehand that I was getting back to Scotty's question, and he did say he was using an NSImageView.
(Last edited by Chuckit; Feb 3, 2003 at 02:51 AM.
)
|
|
Chuck
___
"Instead of either 'multi-talented' or 'multitalented' use 'bisexual'."
|
| |
|
|
|
 |
|
 |
|
Senior User
Join Date: Dec 2001
Status:
Offline
|
|
Originally posted by Chuckit:
Sir, it's not my fault if you have difficulty getting laid. Don't take it out on me. I don't care how 1337 you may think you are; if Andrew Welch and Rick Roe can be polite, you can too.
Damn. You caught me red-handed on all three counts (Can't get laid, 1337n3ss, the fact that I'm normally polite, and probably a fourth, since I'm nowhere near as 1337 as moki or Rickster!). It was 2 AM, but that's no excuse, so I sincerely apologize for being a jackass.
Originally posted by Chuckit:
...I thought he was talking about in the code he posted here--with [super drawRect:rectangle]--which is, of course, correct.
Unfortunately, it's not correct. The documentation for drawRect: in NSView implicitly states "This method is intended to be completely overidden by each subclass that provides it. Don't invoke super's implementation in you subclass." Considering Apple doesn't bother saying "Warning: DO NOT DO THAT", I would assume no bad will come from it, but it is a good idea to conform to convention (even though this convention is different from most other conventions of the same type).
Originally posted by Chuckit:
I wasn't talking to you there. I mentioned right beforehand that I was getting back to Scotty's question, and he did say he was using an NSImageView.
Whoops. I get it now! I would wholeheartedly agree that Apple is not using an NSImageView in iPhoto!
|
|
"Think Different. Like The Rest Of Us."
iBook G4/1.2GHz | 1.25GB | 60GB | Mac OS X 10.4.2
Athlon XP 2500+/1.83GHz | 1GB PC3200 | 120GB | Windows XP
|
| |
|
|
|
 |
|
 |
|
Fresh-Faced Recruit
Join Date: Jun 2000
Location: Oslo, Norway
Status:
Offline
|
|
Originally posted by macmike42:
The documentation for drawRect: in NSView implicitly states "This method is intended to be completely overidden by each subclass that provides it. Don't invoke super's implementation in you subclass." Considering Apple doesn't bother saying "Warning: DO NOT DO THAT", I would assume no bad will come from it, but it is a good idea to conform to convention (even though this convention is different from most other conventions of the same type).
I saw that the documentation said that i shouldn't call super's implementation. But in this particular case, not calling super's implementation caused the entire NSImageView functionality to break -- i.e. it wouldn't displaying the image.
To me, it seemed silly then to rewrite the code needed to display the image. Since subclassing a class is all about retaining functionality I called super's drawRect since I obviously wanted to... er, retain functionality.
But from what you write I now get the feeling that NSImageView perhaps doesn't have the best implementation of this functionality, so maybe I'll write my own anyway.
So thanks to both of you for insightful hints. I'll especially take a look at the compositing operations.
Scotty.
|
|
|
| |
|
|
|
 |
 |
|
 |
|
|
|
|
|

|
|
 |
Forum Rules
|
 |
 |
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
|
HTML code is Off
|
|
|
|
|
|
 |
 |
 |
 |
|
 |
|