How would I make an NSCell with more than one UI element in it and display it in an NSTableView? For NSCells with a single value I could implement tableView:objectValueForTableColumn:row: but I don't know how to do this for NSCells with more than one. At the moment I have an NSView in an NSCollectionView and all the elements are bound to an NSArrayController. But I'd rather have an NSTableView or similar.
I've switched to JAListView for table and outline views in my Mac apps: https://github.com/joshaber/JAListView
It has the advantage of using NSViews for table items instead of NSCells, allowing for greater freedom in implementing your design.
There's a few other alternatives out there too trying to solve similar gaps in NSTableView and its subclasses:
http://groups.google.com/group/cocoa-unbound/browse_thread/thread/87b2a1b5725eac05
You return the primary value in the tableView:objectValueForTableColumn:row: method, and then set up the cell further in tableView:willDisplayCell:forTableColumn:row:.
Either that, or you create a custom NSCell subclass that can customize itself based on the objectValue that you give it.
Related
I have an NSSplitView showing two NSTableView instances. I need to detect which table view has become "active" (of focused), which means the one that the user has clicked. I need to know that because each table view acts as a source list for another view that shows the content of the selected row(s). This other view is shared for both tables.
I could do it by subclassing NSTableView and reacting to mouseDown: or another method but it I'd rather avoid subclassing just for that. I also don't want to track any NSWindow event just to know if the user has clicked one of the tables (I'd rather subclass NSTableView).
Currently, I use the delegate method tableViewSelectionDidChange:, but this method is, obviously, only called when the selected row changes. I need to know that a table becomes active even if the selected row hasn't changed.
Observing the clickedRow property of the table views doesn't appear to work. If may not be KVO compliant.
Any ideas?
For those interested, the most convenient solution I found was to take advantage of the fact that NSTableView is a subclass of NSControl. So just like NSButton it can send action messages when clicked (upon mouse up).
For each tableView, I wired its "action" to the same ibaction selector of my controller object in interface builder.
The controller identifies the sender and acts accordingly.
No need to subclass NSTableView.
I have the following design:
How should I proceed? Add a NSScrollView with the first element, which contains a couple of NSTextFields and an NSImage and then repeat in the code? What type of repeater should I use? And... is NSScrollView able to handle this type of design?
Is it possible to use NSTableView?
Thank you!
I would probably have a custom NSView class that contains the date labels on the left, a NSImage that toggles between two states (selected or not) and the request label on the right. You can lay it out either in code or in a .nib and instantiate it that way respectively.
When you create the superview create four of the new subclasses and put them in the appropriate places.
Only use scroll view if you think that you'll have so many options that you will need to scroll.
I'm trying to implement outline view in my app using NSOutlineView, but in my app the outer layer (parent) should have only one column (Brand) and inner layer (children) should have 5-6 columns (Size,Type,Image, etc.).
Is it possible to achieve, and how to do so if it is?!
Yes, you can have “full-width” cells for “group rows” in a NSOutlineView (or NSTableView).
If you’re using a cell-based outline view, implement outlineView:dataCellForTableColumn:item:
in your NSOutlineViewDelegate. Before this method is invoked with any of the existing columns, it will be invoked with a column of nil. For the corresponding rows, return a prototype NSCell, and in your other data source/delegate methods likewise return the corresponding information for a nil “column”. You just need to create a generic NSTextFieldCell for this; no need to style it yourself unless you want to. More information in the documentation or take a look at some Apple sample code.
If you’re using a view-based outline view, implement the equivalent outlineView:viewForTableColumn:item:. Unfortunately the documentation is currently pretty nonexistent, but the corresponding NSTableViewDelegate method is documented, and you can look at this code sample.
The appearance of the full-width item will vary based on the highlight style (selectionHighlightStyle) configured for your outline view; from your description, it sounds like you would want “regular” rather than “source list” behavior.
This may be a general discussion instead of a real question. When I started using NSTableView and NSOutlineView, I thought : oh, a instance of NSView may do almost everything. So I return a NSView instance in my delegate and dataSource.
Of couse it did not work and I realized that NSTableView consitsts of instances of NSCell which inherits directly from NSObject.
I sensed that it may be important to understand why Cocoa constructed NSTableView based on NSCell but NSView. But few documents explain it clearly. Therefore I turn to Stackoverflow. Does anyone know that? Thank you at advance!
You can switch to a view based NSTableView or NSOutlineView in the inspector
The reason for a cell based cell would be if your only want to display a string. If you only want to display a string it would be a waste of resources to init a whole view to each cell. It is basically about memory control vs. what you need to display.
#d00dle's answer shows how to use an NSView backed table view, but it doesn't answer the question of why NSTableViews historically used NSCells in the first place.
The answer is that NSViews are heavy objects and expensive to manage. NSTableViews typically need many many rows and columns of "view-like" things, and if you naively added them all as actual NSViews, you can't maintain a responsive UI.
This is reflected in the trickiness Apple added to support NSView-backed table and outline views; it creates a limited number of NSViews and recycles them in clever ways to reduce the total number of NSViews in use at any given moment.
I've got an NSTableView that displays (via bindings) data from an NSTreeController. The application frequently appends/changes data to/in the bound array.
The problem is that if the user has selected a row in the table, but has scrolled so that the selected data is no longer visible, when the application updates the array it causes the display to auto-scroll so that the selected line is once again on screen. This is pretty
frustrating to users, especially since new data can arrive at any time.
Is there any way of disabling this feature?
You may have to subclass NSTableView and override -scrollRowToVisible:, temporarily bracketing the call to super. This may also require a custom BOOL ivar in your subclass to keep track of whether you want to scroll.
I would start by setting a breakpoint there to see when exactly the autoscroll is triggered. This should help to find the proper moments to toggle the ivar.
Are you using an NSTreeController with an NSOutlineView or an NSArrayController with an NSTableView? Using an NSTreeController with an NSTableView doesn't make a lot of sense to me?
If you're using an NSTableView you should probably be using an NSArrayController to manage its data and this rearranging of the rows is a feature of the NSArrayController. Try turning off the Auto Rearrange Content option on your controller within IB.
When it's on, the array controller will rearrange its objects on addition, removal and changes to objects that would affect the sort ordering (if any) and cause any table views or outline views to reload their data.
I don't know of a similar feature for NSTreeController mainly because I don't use it since it's never worked well for me. I, sadly, recommend to just use the datasource methods for the NSOutlineView and supply your data the old-fashioned way. In my experience, NSTreeController is only well suited for the most trivial tasks.