 |
 |
What's this called and how do I do it?
|
 |
|
 |
|
Addicted to MacNN
Join Date: Nov 2002
Location: Seattle, WA
Status:
Offline
|
|
I can't think of what to call this. I've found numerous methods to manipulate "highlighting" and "selection" but neither of those states seem to be this.
Here's the problem. In order to implement tableview row coloring I was using the delegate method willDisplayCell:NSCell yadda yadda yadda. but that didn't fill in the empty rows and had other problems as well. So I started in with the NSTableView subclass found here:
http://members.iinet.net.au/~tonyarn...es/000015.html
but now when cells are edited they don't have that nice blue glow, which I would call "highlighting", but apparently Apple uses that term to describe what I would call "selection", where the cell gets the color of selected rows. Anyway, here's what my cells look like now:
and here's what they're supposed to look like:
how do I do this? (and while we're at it, does anyone know what it's called?)
(Last edited by Uncle Skeleton; Jun 7, 2003 at 03:35 PM.
)
|
|
|
| |
|
|
|
 |
|
 |
|
Clinically Insane
Join Date: Oct 2001
Location: San Diego, CA, USA
Status:
Offline
|
|
It's called the keyboard focus ring. As far as I know, Apple doesn't provide any direct method for drawing it, but it's not that hard to do it yourself. Here's a basic drawRect: method that will draw a focus ring around a view:
Code:
- (void)drawRect:(NSRect)aRect
{
NSRect rectToFocus = [self bounds];
[NSGraphicsContext saveGraphicsState];
NSSetFocusRingStyle(NSFocusRingOnly);
NSRectFillUsingOperation(rectToFocus, NSCompositeSourceOver);
[NSGraphicsContext restoreGraphicsState];
}
|
|
Chuck
___
"Instead of either 'multi-talented' or 'multitalented' use 'bisexual'."
|
| |
|
|
|
 |
|
 |
|
Addicted to MacNN
Join Date: Nov 2002
Location: Seattle, WA
Status:
Offline
|
|
|
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status:
Offline
|
|
Is there a simple tutorial on using custom views in tables and browsers, etc? I can't find any and would like to implement a tableView that has an NSProgressIndicator in one column.
|
|
you are not your signature
|
| |
|
|
|
 |
|
 |
|
Addicted to MacNN
Join Date: Nov 2002
Location: Seattle, WA
Status:
Offline
|
|
I don't know if it will work, but you can try [NSTableColumn setDataCell:[[NSProgressIndicator alloc] init]]
|
|
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Dec 2000
Location: Chicago, Illinois
Status:
Offline
|
|
Originally posted by Uncle Skeleton:
I don't know if it will work, but you can try [NSTableColumn setDataCell:[[NSProgressIndicator alloc] init]]
1) You should autorelease the ProgressIndicator as well.
2) NSProgressIndicator isn't a subclass of NSCell, so you can't make it the data cell.
What you should do instead is make a custom subclass of NSCell and implement the behavior yourself. You might want to search the internet to see if someone else has already done this - I know that Acquisition does.
Matt Fahrenbacher
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status:
Offline
|
|
Originally posted by Gametes:
Is there a simple tutorial on using custom views in tables and browsers, etc? I can't find any and would like to implement a tableView that has an NSProgressIndicator in one column.
I don't know of a tutorial, but to do this (it's pretty easy), you need to make an NSCell that encapsulates an NSView. The NSCell's drawWithFrame:inView: selector will lockFocus on the encapsulated view, call it's drawRect: method, and then unlockFocus on it.
If you wanted to use a view that responded to keyboard and mouse input, you'd need to use an NSActionCell instead of an NSCell and pass the events along to the encapsulated view.
|
Geekspiff - generating spiffdiddlee software since before you began paying attention.
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status:
Offline
|
|
I created an NSCell subclass, and added it to IB. But I can't instantiate it! How do I connect my NSTableColumn's dataCell outlet to the NSCell?
|
|
you are not your signature
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Dec 2000
Location: Chicago, Illinois
Status:
Offline
|
|
Originally posted by Gametes:
I created an NSCell subclass, and added it to IB. But I can't instantiate it! How do I connect my NSTableColumn's dataCell outlet to the NSCell?
I've never been able to do that either, so I just instantiated it in my code manually. Just add it to your applicationDidFinishLaunching: or what not. But if there's a way to instantiated NSCell subclassess in IB, I'd love to hear it.
Matt Fahrenbacher
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status:
Offline
|
|
Ok, I ended up with this:
Create an NSCell subclass. Import it into your controller class or whatever. create an instance there. In ApplicationDidFinishLaunching, execute
[[myTable tableColumnWithIdentifier:@"Identifier"] setDataCell:myCell];
myCell should have at least 1 method,
Code:
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
NSProgressIndicator *indicator = [[NSProgressIndicator alloc] init];
//NSRect newFrame = cellFrame;
cellFrame.size.height = 10;
[indicator setStyle:NSProgressIndicatorBarStyle];
[indicator setControlSize:NSSmallControlSize];
[indicator setIndeterminate:NO];
[indicator setFrame:cellFrame];
[controlView addSubview:indicator];
}
This works great for me!
|
|
you are not your signature
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status:
Offline
|
|
Originally posted by Gametes:
Ok, I ended up with this:
Create an NSCell subclass. Import it into your controller class or whatever. create an instance there. In ApplicationDidFinishLaunching, execute
[[myTable tableColumnWithIdentifier:@"Identifier"] setDataCell:myCell];
myCell should have at least 1 method,
[snip]
This works great for me!
Your code leaks an NSProgressIndicator every time it draws the cell. No good...
You should probably put the code you've currently got in drawInteriorWithFrame into your NSCell subclass's initTextCell or initImageCell (whichever you're calling from your controller). Then, do something like this:
Code:
- (void)drawInteriorWithFrame: (NSRect)cellFrame inView: (NSView *)controlView {
[myProgressIndicator setFrame: cellFrame];
// we've got focus locked on controlView already, which is where we want to draw
[myProgressIndicator drawRect: [myProgressIndicator bounds]];
}
|
Geekspiff - generating spiffdiddlee software since before you began paying attention.
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status:
Offline
|
|
Well, my controller never calls the init methods. That's what the table does, right?! I don't even know how to find out which it's using. My delegate just waits till it's asked to draw a cell, then it does what's above.
Are you saying every time it redraws the cell there's a new leak? Because I thought the tableView reused old cells? I still beleive you, but that's odd.
Also, after I've drawn all these progress indicating cells, how do I get to them to increment them? I have the index number of the right row, I think, but even with that info I can't find a method set like
Code:
[[[tableView tableColumnForIdentifier:@"Identifier"] cellAtIndex:index] incrementIndicator:percent]
where incrementIndicator is a method implemented by my custom dataCell class. There just seems no way to retreive a particular cell to work on it...
Thanks
|
|
you are not your signature
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Dec 2000
Location: Chicago, Illinois
Status:
Offline
|
|
Oh, I see what's happening. The draw method gets called A LOT, aka each time the cell needs to update it's display. So, each time that display happens, you create a new NSProgressIndicator and add it as a subview of the controlView (which now technically means the progress indicator now has a retain count of 2). This is a memory leak, definitely. Also, each new progress indicator you add will be rendered ontop of the previous progress indicator, which could explain the problems you were having incrementing the progress indicator.
Here's what I would do:
Code:
- (id)init
{
self = [super init];
if(self)
{
myProgressIndicator = [[NSProgressIndicator] alloc] init];
}
return self;
}
- (void)dealloc
{
[myProgressIndicator autorelease];
[super dealloc];
}
then use smerger's draw code as stated above.
Hope this helps,
Matt Fahrenbacher
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status:
Offline
|
|
I see the logic here, and have the code looking as specified. But I'm getting what I think is 17 ProgressIndicators drawn on top of each other in the upper left hand corner of the tableview.
debug?
Code:
#import "ProgressCell.h"
@implementation ProgressCell
- (id)init
{
self = [super init];
indicator = [[NSProgressIndicator alloc] init];
[indicator setStyle:NSProgressIndicatorBarStyle];
[indicator setControlSize:NSSmallControlSize];
[indicator setIndeterminate:NO];
[indicator setDisplayedWhenStopped:YES];
return self;
}
- (void)dealloc
{
[indicator autorelease];
[super dealloc];
}
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
//NSRect newFrame = cellFrame;
//cellFrame.size.height = 10;
//[controlView addSubview:indicator];
[indicator setFrame:cellFrame];
[indicator drawRect: [indicator bounds]];
}
- (IBAction)incrementIndicator:(double)percent
{
[indicator incrementBy:percent];
}
@end
|
|
you are not your signature
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Dec 2000
Location: Chicago, Illinois
Status:
Offline
|
|
Well, fron what I can tell, NSProgressIndicator isn't in a view anywhere, so I wonder if that's causing a problem. I mean, what does setFrame: end up doing to a view that isn't a subview of anything? WOuldn't that place it at the frame in the screen coordinate system?
That might mean you need to translate the cellFrame from the controlView coordinate system to that of the screen, but I'm just guessing here.
Something else to think about
Matt Fahrenbacher
|
|
|
| |
|
|
|
 |
|
 |
|
Clinically Insane
Join Date: Oct 2001
Location: San Diego, CA, USA
Status:
Offline
|
|
In addition to what Matt said, you're calling drawRect: on an unfocused view. Besides it generally being a bad idea to call drawRect: at all (because the drawing might not be flushed to the screen properly), this means the coordinate system it's drawing into is that of the currently focused view--the table view. You'll want to call display instead.
|
|
Chuck
___
"Instead of either 'multi-talented' or 'multitalented' use 'bisexual'."
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status:
Offline
|
|
I don't understand where I should put the display method, and who am I sending it to?
Could you take a stab at editing the above code so that it should function? I think only the drawInterior method needs revising, right?
|
|
you are not your signature
|
| |
|
|
|
 |
|
 |
|
Clinically Insane
Join Date: Oct 2001
Location: San Diego, CA, USA
Status:
Offline
|
|
Originally posted by Gametes:
I don't understand where I should put the display method, and who am I sending it to?
Could you take a stab at editing the above code so that it should function? I think only the drawInterior method needs revising, right?
Yeah, I'd think so. It should look something like this:
Code:
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
if ([indicator superview] != controlView)
{
[controlView addSubview:indicator];
}
[indicator setFrame:cellFrame];
[indicator display];
}
(Last edited by Chuckit; Jun 10, 2003 at 03:54 PM.
)
|
|
Chuck
___
"Instead of either 'multi-talented' or 'multitalented' use 'bisexual'."
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Dec 2000
Location: Chicago, Illinois
Status:
Offline
|
|
Oh wow, I didn't even notice you were calling drawRect: - I've never seen anyone do that before! You almost always call display or setNeedsDisplay: instead of invoking drawRect: directly.
Does Chuckit's code work for you now?
Matt Fahrenbacher
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status:
Offline
|
|
I really appreciate this guys. But still it's a no go.
my code is now
Code:
#import "ProgressCell.h"
@implementation ProgressCell
- (id)init
{
self = [super init];
indicator = [[NSProgressIndicator alloc] init];
[indicator setStyle:NSProgressIndicatorBarStyle];
[indicator setControlSize:NSSmallControlSize];
[indicator setIndeterminate:NO];
[indicator setDisplayedWhenStopped:YES];
return self;
}
- (void)dealloc
{
[indicator autorelease];
[super dealloc];
}
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
if ([indicator superview] != controlView)
{
[controlView addSubview:indicator];
}
[indicator setFrame:cellFrame];
[indicator display];
/*
//NSRect newFrame = cellFrame;
cellFrame.size.height = 10;
[indicator setFrame:cellFrame];
if ( [[controlView subviews] lastObject] != indicator )
[controlView addSubview:indicator];
//[controlView display];
//[indicator drawRect:[controlView bounds]];
*/
}
- (IBAction)incrementIndicator:(double)percent
{
[indicator incrementBy:percent];
}
@end
And I have an instance of ProgressCell *progressCell in controller.h, then in ApplicationDidFinishLaunching progressCell = [[ProgressCell alloc] init];
and [[moviesTable tableColumnWithIdentifier:@"Progress"] setDataCell  rogressCell];
Right after my table receives the signal to reload, but in the above drawing code, it gets a sigsev error I'm investigating.
hmmm...
|
|
you are not your signature
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status:
Offline
|
|
I think it's possible to do this in a very lightweight manner, which is what motivated my earlier code.
Caveat - I haven't tried this, so I'm not sure it works.
The rationale is that before drawInteriorWithFrame is called, the owning control already has focus locked on it. So, any drawing that you do already has a well-defined frame and coordinate system - those of the owning control. This means that when you tell the progress indicator to draw itself, it draws itself into the owning control's view, using its coordinate system.
There's no need to actually insert the progress indicator into the view hierarchy. In fact, it's desirable not to, in that it makes all of the event processing much quicker when there aren't a billion views floating around.
So, I think my original code works, provided you slide the coordinate system around.
Second attempt, still untested:
Code:
- (void)drawInteriorWithFrame: (NSRect)cellFrame inView: (NSView *)controlView {
[indicator setFrame:cellFrame];
NSPoint originalBoundsOrigin = [controlView bounds].origin;
NSPoint cellFrameOrigin = cellFrame.origin;
[controlView setBoundsOrigin: NSMakePoint(-cellFrameOrigin.x, -cellFrameOrigin.y)];
[indicator drawRect: [indicator bounds]];
[controlView setBoundsOrigin: originalBoundsOrigin];
}
Here's what's happening. On entry, we're guaranteed that [controlView lockFocus] has been called. Set the indicator's frame to cellFrame so that when we ask it to draw itself, it knows how large it should be. Save the original coordinate system origin so that we can restore it when we're done. Then, move the coordinate system origin so that the point (0,0) corresponds to the point cellFrameOrigin when viewed through the controlView's frame (this is tricky). Ask the indicator to draw itself in its entirety (by passing it its entire bounds rectangle). Finally, restore the original coordinate system.
I may have flipped a minus sign in there somewhere. I always have a hard time visualizing coordinate systems sliding around on top of each other.
|
Geekspiff - generating spiffdiddlee software since before you began paying attention.
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status:
Offline
|
|
That's almost there. It draws them all great (thanks so much), but they're
A) really big. They fill the whole cell. I can probably figure out how to shrink them.
B) They are getting really thick black borders when I scroll the tableView... this is probably because they are being drawn overtop of one another constantly. Perhaps this isn't the right way to go?
C) Can I access them to increment the progress? How do I get a particular cell out of a column with only its index?
(Last edited by Gametes; Jun 10, 2003 at 09:19 PM.
)
|
|
you are not your signature
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Norfolk, Va
Status:
Offline
|
|
Chuck: when I use this code, it only draws the progress indicator in the last cell in the tableView and in whatever row is currently selcted. I bring it up because this looks to be the cleanest method so far, so I'd like to see it function for posterity.
Why do you think it only displays when selected?
Originally posted by Chuckit:
Yeah, I'd think so. It should look something like this:
Code:
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
if ([indicator superview] != controlView)
{
[controlView addSubview:indicator];
}
[indicator setFrame:cellFrame];
[indicator display];
}
|
|
you are not your signature
|
| |
|
|
|
 |
 |
|
 |
|
|
|
|
|

|
|
 |
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
|
|
|
|
|
|
 |
 |
 |
 |
|
 |
|