Re: NSMatrix
Re: NSMatrix
- Subject: Re: NSMatrix
- From: Dave Hersey <email@hidden>
- Date: Wed, 26 Mar 2008 14:40:52 -0400
On Mar 26, 2008, at 11:52 AM, Matthew Miller wrote:
Could some please explain in simple terms how to create a NSMatrix
which distributes cells in rows based on the input of a table and
takes away the cells when it is not needed. Thank you very much!
P.S. I am new to cocoa so please don't use really big and complex
cocoa vocab, but then again, I would appreciate anything! :)
The problem is that NSMatrix is not a beginner class. If you don't
have a solid understanding of other Cocoa frameworks like NSControl,
NSView, NSCell (and its variants- NSActionCell, NSImageCell), and if
you aren't comfortable subclassing yet, you're going to have a lot of
trouble with NSMatrix.
But, here's what you need to do.
First, you need to do some design.
1. Create a subclass for the data that goes in the cells. While not
strictly necessary (e.g. you could create a matrix of strings using
just NSString as the object class), you almost always will want to do
this. Typically you'll have information that won't be displayed, such
as a path to an image, and you'll want to keep that connected to the
data you are displaying. So, we'll create an NSObject subclass to hold
our data and call it ThumbnailObject.
2. Decide where you're going to store that data. NSArrayController is
a great way to manage contents of an NSMatrix, but if you're not
familiar with that, I'd go with an NSMutableArray for now. Your
ThumbnailObjects will be stored in the array as they are created, and
removed from it when they're tossed aside. The Matrix will reflect the
objects that are stored in this array.
3. Decide what your cell class will be for the matrix. For example, if
you were displaying a bunch of images, you might use NSImageCell. If
you were displaying text, you might use NSTextFieldCell. If you're
displaying checkboxes, you might use NSButtonCell. However, unless
your matrix needs are very basic, you'll probably want to subclass
this base cell class. Do you absolutely need to? Maybe not, but it
will probably make your code easier to follow and maintain. So, let's
say you're going to display images. You'd probably want to subclass
NSImageCell or NSActionCell for that. Which you choose is an
implementation detail, and determines the methods you need to override
or provide in order to have the cell behave the way you want. For this
discussion, we'll create a subclass of NSImageCell called ThumbnailCell.
4. Create a subclass of NSMatrix. You'll almost certainly need this,
since NSMatrix is a rather peculiar class that almost feels
"unfinished" when you get working with it. We'll call our subclass of
NSMatrix ThumbnailMatrix.
So, in this design, you have a ThumbnailMatrix which contains
ThumbnailCells that display data from ThumbnailObjects. You've created
subclasses of NSMatrix, NSImageCell and NSObject to do this.
You've got to get the design above nailed down before going any
further. If any of that is confusing or doesn't make sense to you,
read up on the classes mentioned above before proceeding.
Now you code.
5. Code the subclasses.
The ThumbnailMatrix class is going to have the following methods:
initWithFrame - Create an instance of ThumbnailCell and pass it to the
superclass's initWithFrame method as the prototype cell for your matrix.
awakeFromNib - Here, I'd set up things like interCellSpacing,
cellSize, autoScroll, etc.
renewRowsIfNeeded - This is a method I create that checks to see if
the number of cells that can fit on the rows has changed or if the
width between them has changed. (I usually spread the extra space at
the end of the row between the cells to make them appear evenly
distributed.) Get the cell size and the super view's bounds, then
determine how many rows and columns fit. Get the "left over" space
from a full row and use that to determine what the interCell spacing
should be, then set the interCell spacing if it's different. Compare
the number of rows and columns to what you already have. If they're
different you need to call renewRows. Return true if the intercell
spacing changed or renewRows was called.
setFrameSize - Override this if you want to have the matrix do live
rebuilding as you grow or shrink the window. If you don't do this, the
matrix will stay it's old size until the mouse button is released, at
which point it will change its number of rows and columns to fit
(because of viewDidEndLiveResize below). It looks nice to have the
matrix change to reflect the final state while you're dragging, so I'd
implement this. It should call it's super then, if renewRowsIfNeeded
returns true, call sizeToCells. Then call setNeedsDisplay (or
setNeedsDisplayInRect if you're optimizing for live resizing.) Do
setNeedsDisplay for now, then look into live resizing optimization.
viewDidEndLiveResize - When the mouse is released after a resize, this
method is called. If renewRowsIfNeeded returns true, then call
sizeToCells, setNeedsDisplay.
rebuildThumbnailMatrix - This is a method I'd implement to get your
data into the matrix. It basically needs to go through the array
mentioned in step 2, create enough cells if there aren't enough
already, then store a ThumbnailObject in each cell. At the end, you
need to do the renewRowsIfNeeded, sizeToCells, setNeedsDisplay mantra.
There are several other things you'll probably end up wanting to do,
for example to support drag and drop. But, get this stuff working
first and then search the lists about that.
The ThumbnailCell class is going to have these methods:
dealloc - releases stored thumbnailObject, calls super
copyWithZone - returns a new cell from super copyWithZone, retaining
the ThumbnailObject and storing that in the new cell
thumbnailObject - returns the stored thumbnailObject
setThumbnailObject - stores the cell's thumbnailObject
image - returns the stored thumbnailObject's image
setImage - sets the stored thumbnailObject's image and sends it to
super setImage
drawInteriorWithFrame - if no thumbnailObject is set, drops out. (A
matrix can have unused cells at the end of the last row) Otherwise,
checks to see if [super image] == [self image]. If not, call [super
setImage: [self image]] to store the thumbnailObject's image in the
super. Either way, call super drawInteriorWithFrame if the thumbnail
object for the cell is not nil.
You'll probably want to override more methods to control drawing.
The ThumbnailObject class is going to simply have storage and
accessors for your thumbnail data. In this case you might have
init - create an NSMutableDictionary to hold the object's data
dealloc - clean up
image - return the dictionary's entry for the object's image
setImage - store the passed image in the dictionary
pathToImage - return the dictionary's entry for the image's path.
setPathToImage - store the passed image path in the dictionary
This is by no means an optimal way to do things since eventually you'd
have all of your images in memory. However, you could implement some
"smarts" to unload images that are well out of view range and reload
them when they're asked for, etc. Get it working, then optimize it.
So, at this point you have all of your classes created. In your app
controller, you'll need an outlet to your matrix. At some point you'll
call rebuildThumbnailMatrix (above) with the data you want to put in
the matrix. If you delete objects or add more later, you'll want to
call rebuildThumbnailMatrix again.
Now you create a matrix in InterfaceBuilder.
6. Go to Interface Builder and create a matrix in a window. In IB3
you'll create an instance of an NSImageView and then embed it in a
matrix and then embed that in a scroll view. Change the matrix's type
to ThumbnailMatrix. Connect your application controller's outlet to
the matrix.
7. Build and debug and debug and debug.
8. Debug more, you missed something.
9. It works, optimize, you're done.
Of course there are other ways to do some of this, but that's the
basic approach you'll need to follow.
I think this is probably way beyond where you're at right now with
Cocoa, but use it as a guide for how to approach learning the
material. It probably looks overwhelming, but once you're comfortable
with the underlying Cocoa frameworks it will be manageable.
- d
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
References: | |
| >NSMatrix (From: Matthew Miller <email@hidden>) |