Re: Creating NSTableView programmatically
Re: Creating NSTableView programmatically
- Subject: Re: Creating NSTableView programmatically
- From: corbin dunn <email@hidden>
- Date: Thu, 14 Dec 2017 15:06:13 -0800
> On Dec 12, 2017, at 2:12 AM, Eric Matecki <email@hidden> wrote:
>
> Hi,
>
> On 11/12/2017 20:10, Quincey Morris wrote:
>>> I made my own text field class according to this (in NSTableCellView's doc)
>>> :
>>
>> I think you’re still kinda Doing It Wrong™. The standard (and, I believe,
>> recommended) way to do this is to create an instance of
>> NSTableCellView, which has the “objectValue” property, along with other
>> potentially useful behaviors for cell views (such as
>> identifiers that allow the NSTableView to cache and manage cell views).
>
> I know it's wrong, or at least bad, but NSTextView and NSButton are the
> controls I kind of master right now...
> I really don't need a textview, as I'm just trying to reproduce the
> "Combattant" example.
> I still can't get the names to display with NSTableCellView.
>
> Here (at the bottom of the page) :
> https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/TableView/PopulatingViewTablesWithBindings/PopulatingView-TablesWithBindings.html
> it says :
> """
> When you make the connection to the table view’s Content binding, the
> objectValue property of the NSTableViewCell used as the cell for the table
> column is configured such that for each item in the model array, the table
> updates the objectValue property to the current row’s Person object
> 1) Select the text field in the table column cell and create the binding.
> All bindings of subviews in the cell are made to the objectValue.
> Configure the textField instance’s value binding.
>
> Binding field | Value
> -----------------------------------
> Bind to: | Table Cell View
> Model key path | objectValue.name
> """
>
> So I have this in my NSTableView's delegate, which is my interpretation of
> the above :
>
> - (NSView *)tableView:(NSTableView *)tableView
> viewForTableColumn:(NSTableColumn *)tableColumn
> row:(NSInteger)row
> {
> #if 0 // this shows the names
>
> cTextView* view = [[cTextView alloc] init]; // cTextView is my custom
> NSTextView with just an added objectValue property
> [view bind: @"value" toObject: tableView withKeyPath:
> @"objectValue.name" options: 0]; // wrong, but works
> //[view bind: @"value" toObject: view withKeyPath: @"objectValue.name"
> options: 0]; // right, works
>
> #else // this doesn't show the names
>
> NSTableCellView* view = [[NSTableCellView alloc] init];
> //[[view textField] setBackgroundColor: [NSColor redColor]]; // just to
> be sure to see it when empty... nada
> //[[view textField] bind: @"value" toObject: tableView withKeyPath:
> @"objectValue.name" options: 0]; // wrong, doesn't work
> [[view textField] bind: @"value" toObject: view withKeyPath:
> @"objectValue.name" options: 0]; // right?, but doesn't work
^ This is correct, but the piece you are missing is somehow providing the
objectValue for the resulting tableCellView.
NSTableView sets the objectValue to the result from the table’s content
binding. It does this on the result you return from the above method. However,
I recommend just implementing tableView:objectValueForTableColumn:row: in your
delegate and returning something. The “something” you are turning has to be an
object that has a “name” property (based on your binding). You could just bind
it to “objectValue” and return a (cached) string.
corbin
>
> #endif
> return view;
> }
>
> Note that I bind the NSTextView to tableView, while the doc says "the
> objectValue property of the NSTableViewCell", not of the tableview... but it
> works, and I don't understand why... I don't like it when I don't understand
> what's happening.
> It also works when binding to the view, which is expected (I first bound it
> to tableView by mistake...).
> It's still weird (to me) to bind an object's binding to one of it's own
> properties.
> I guess it's more or less by chance that it displays the names, and that some
> changes in my model won't get correctly propagated...
>
> In the case of NSTableCellView, neither binding works... I don't get any
> exception or crash, but nothing is displayed inside my table view (although
> it's size suggests the four rows are there).
> But setting the backgroud of the textfield to red doesn't show any red on the
> screen...
> (Trying to the set the cell's background gives me a "may not respond to
> message" warning, and obviously nothing gets red on the screen).
>
> Something in the "big scheme of things" escapes me, and Apple's doc was not
> very helpful until now.
>
>> In a very unusual or complex case, you might subclass NSTableCellView to add
>> properties or behaviors to it, but it’s normally not
>> necessary. Custom properties, for example, can be carried around by the
>> object referred to by “objectValue”, and custom behaviors
>> can sometimes be implemented as part of the delegate.
>>
>> Instead of using a cell view other than a NSTableCellView or subclass, it’s
>> usual to *add subviews* for things like text fields
>> and buttons. That separates the behavior of the cell *as a cell* (such as
>> being cached for the table view) from the view hierarchy
>> represented by the cell. However, if your cell just needs to contain a text
>> field, you don’t need to add one yourself,
>> because NSTableCellView already contains a NSTextField subview that you can
>> just *use*. It also contains NSImageView subview that
>> you can use or ignore.
>
> How do you "ignore" what you don't need in an NSTableCellView ?
> And when I add a subview to one, how do I arrange (layout) it's content, so
> it works with the way the 'free' NSTextField and NSImageView are arranged
> (which I ignore) ?
> NSTableCellView's doc is rather scarce.
>
>>> Now I can see all the names :)
>>
>> One reason to use a NSTableCellView instead of a control sum as a text field
>> is that the cell view’s size is *forced* to the
>> dimensions required by the table view row. That means you have no control of
>> the placement of the contents relative to the row.
>> For a text field, for example, you have no direct way of controlling the
>> margins surrounding the text. This approach also limits
>> the use of autolayout, which may or may not be an issue in your project.
>>
>>> - (NSView *)tableView:(NSTableView *)tableView
>>> viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
>>> NSTextView* view = [[NSTextView alloc] init];
>>> …
>>
>> You say “text field” everywhere, but you actually create a text view. I
>> don’t get a sense of which one you really want to use, but
>> using a separate NSTextView for each row of the table could end badly, and
>> subclassing NSTextView is probably a code smell.
>
> I'm using an NSTextView, but just because I can make it kind of work...
> Calling them text fields is a bad habit of mine (especially since there IS an
> NSTextField), sorry.
>
> Thanks for your efforts.
>
> Eric M.
>
> --
> Keep intel OUTSIDE my Mac !
> Hiii !!! I can see Intel chips creeping around my G5 !
>
> Eric M.
> _______________________________________________
>
> 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
_______________________________________________
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