Line Numbers in Tables

  • Simple function --  apparently no simple solution.  I just want to put
    line numbers in one column of a table.  I want them to start at "1" and stop
    at the last table entry.  Nothing I've tried works and I've searched
    available resources.

        I have an object hierarchy with multiple table, outline, and browser
    views which I have now successfully implemented with NSArrayController and
    NSTreeController using bindings (wasn't easy, but I did it).  I even
    overrode (overrided?) "add" to allow popup button selection of "first",
    "last", "at selection", and "after selection" in each of the views and to
    add the correct class as per level.
  • On Aug 29, 2007, at 11:07 AM, Gordon Apple wrote:

    > Simple function --  apparently no simple solution.  I just want
    > to put
    > line numbers in one column of a table.  I want them to start at "1"
    > and stop
    > at the last table entry.  Nothing I've tried works and I've searched
    > available resources.

    Tables are inside NSScrollViews.  NSScrollViews can have rulers, and
    rulers can be used for line numbers, so I'd look at tackling from
    that approach.

    Basically, make a subclass of NSTableView and a subclass of
    NSRulerView (which communicates with the table view).  In the table
    view's awakeFromNib, create the ruleview and set the vertical ruler
    of the table's enclosing scroll view  to that.  The ruler view would
    call the table view's rowAtPoint to find the first visible row,
    rectOfRow to figure out each row location (until it was off the ruler
    view's visible rect).

    This will give you the advantage that the line number is always
    visible (and not scrolled away like a column would be).

    Glenn Andreas                      <gandreas...>
      <http://www.gandreas.com/> wicked fun!
    quadrium2 | build, mutate, evolve, animate  | images, textures,
    fractals, art
  • On Wed, August 29, 2007 12:07 pm, Gordon Apple said:
    > Simple function --  apparently no simple solution.  I just want to put
    > line numbers in one column of a table.  I want them to start at "1" and
    > stop at the last table entry.  Nothing I've tried works and I've searched
    > available resources.

    Have you tried returning the row number in the
    tableView:objectValueForTableColumn:row: datasource method?  I'd think
    that should work...

    Something along the lines of:

    tableView:table objectValueForTableColumn:column row:row {
      if ([column identifier] == <number_column>) {// Obviously this is wrong.
          return [NSNumber numberWithInt:row];
      }
    }

    (You many want row+1, of course.)

    This of course means you are using a datasource and not bindings/KVC, but
    the difference isn't all that great...

    Daniel T. Staal

    ---------------------------------------------------------------
    This email copyright the author.  Unless otherwise noted, you
    are expressly allowed to retransmit, quote, or otherwise use
    the contents for non-commercial purposes.  This copyright will
    expire 5 years after the author's death, or in 30 years,
    whichever is longer, unless such a period is in excess of
    local copyright law.
    ---------------------------------------------------------------
  • I haven't used data sources yet and decided to plunge headlong into
    Bindings, which after a steep learning curve and a lot of experimentation
    has proved viable.  My data structure has virtually no code and I have only
    had to subclass NSArrayController and NSTreeController to override the "add"
    function, and that was to support my popup that says where to insert.  Of
    course, with NSTreeController, the later required a lot of futzing around
    with paths plus a hard-coded switch statement of object types per path
    length.

        I was hoping to do this without messing with the views.  The controllers
    obviously have internal access to everything I need, but I haven't found a
    way to get at it and make them do what I want.

        Although line numbers would be good in outline view, they would be
    harder to do.  I would be happy to just get them in my table views (one for
    each level in the hierarchy).  I could maybe get indices from
    "arrangedObjects" and increment by one.  The problem is that I haven't been
    able to figure out a keyPath and function that will allow a binding to
    enumerate the rows of the bound column.  IMHO, this is something that should
    be built into the controllers.  I'm sure I'm not the only one who would like
    line numbers.

    > On Wed, August 29, 2007 12:07 pm, Gordon Apple said:
    >> Simple function --  apparently no simple solution.  I just want to put
    >> line numbers in one column of a table.  I want them to start at "1" and
    >> stop at the last table entry.  Nothing I've tried works and I've searched
    >> available resources.
    >
    > Have you tried returning the row number in the
    > tableView:objectValueForTableColumn:row: datasource method?  I'd think
    > that should work...
    >
    > Something along the lines of:
    >
    > tableView:table objectValueForTableColumn:column row:row {
    > if ([column identifier] == <number_column>) {// Obviously this is wrong.
    > return [NSNumber numberWithInt:row];
    > }
    > }
    >
    > (You many want row+1, of course.)
    >
    > This of course means you are using a datasource and not bindings/KVC, but
    > the difference isn't all that great...
    >
    > Daniel T. Staal
    >
  • On Aug 29, 2007, at 1:07 PM, Gordon Apple wrote:

    > Although line numbers would be good in outline view, they would be
    > harder to do.  I would be happy to just get them in my table views
    > (one for
    > each level in the hierarchy).  I could maybe get indices from
    > "arrangedObjects" and increment by one.  The problem is that I
    > haven't been
    > able to figure out a keyPath and function that will allow a binding to
    > enumerate the rows of the bound column.
    >
    Use the data source method as Daniel suggested...

    mmalc
  • On 8/29/07, mmalc crawford <mmalc_lists...> wrote:
    >
    > Use the data source method as Daniel suggested...

      It's also often overlooked that you can (and, in my experience,
    often *must*) mix table data source methods with bindings to get the
    desired result. This can't be stressed enough: Bindings does not solve
    everything! :-)

    --
    I.S.
  • On 29 Aug 2007, at 17:07, Gordon Apple wrote:

    > Simple function --  apparently no simple solution.  I just want
    > to put
    > line numbers in one column of a table.  I want them to start at "1"
    > and stop
    > at the last table entry.  Nothing I've tried works and I've searched
    > available resources.

    This is what works for me:

    I bind the value binding of the line number column of the tableview
    to the relevant arraycontroller using a path to a method implemented
    in the object controlled by the controller".  (Wow, wasn't that a
    mouthful! In short, something like: value = arrangedIndex.listIndex
    [YourController].)

    The method in your controller object can be something to the extent of:

    - (unsigned)listIndex
    {
    return [myArrayObject indexOfObject:self] + 1;
    }

    Good luck!
    António

    ----------------------------------------------------
    There is a world of difference between
    searching for happiness and choosing
    to be happy.
    ----------------------------------------------------
  • On Aug 29, 2007, at 1:57 PM, Antonio Nunes wrote:

    > I bind the value binding of the line number column of the tableview
    > to the relevant arraycontroller using a path to a method implemented
    > in the object controlled by the controller".  (Wow, wasn't that a
    > mouthful! In short, something like: value = arrangedIndex.listIndex
    > [YourController].)
    > The method in your controller object can be something to the extent
    > of:
    > - (unsigned)listIndex
    > {
    > return [myArrayObject indexOfObject:self] + 1;
    > }
    >
    Don't do this.
    It violates MVC -- it ties the implementation of the model object to a
    particular interface configuration.
    (What happens when a given object is displayed in more than one table
    view?)

    mmalc
  • On 29 Aug 2007, at 22:08, mmalc crawford wrote:

    > Don't do this.
    > It violates MVC -- it ties the implementation of the model object
    > to a particular interface configuration.
    > (What happens when a given object is displayed in more than one
    > table view?)

    I'm not sure if follow this. How so? The listindex is just a property
    of the model object, to which binding is 'legal' afaik.

    I did have a typo in my answer though. Maybe that muddled things up a
    bit:
    > The method in your controller object can be something to the extent
    > of:

    should read:
    The method in your controlled object...etc.

    I.e: The object with the listIndex method is the object being tracked
    by the array controller, not the array controller itself. And the
    myArrayObject in

    > return [myArrayObject indexOfObject:self] + 1;

    is a model object that is an array, although it might be an indirect
    reference rather than direct as in the quoted example.  In my app it
    looks something akin to this:

    @interface MyDocument : NSDocument
    {
    NSMutableArray *myArrayOfObjects; // ArrayController is bound to this.
    }

    ----------

    @interface MyObjectStoredInAnArray : NSObject  // ArrayController's
    Object Class Name is set to this class
    {
    id myDocument;
    }

    @implementation MyObjectToBeStoredInAnArray

    - (int)listIndex // The property to be bound to in the table view column
    {
    return [[mydocument myArrayOfObjects] indexOfObject:self] + 1;
    }

    @end

    Of course the model object stored in the array does need to have a
    reference back to a model object that gives it access to the required
    information, as in the above. So the listIndex always returns a value
    that is accurate within the model, regardless of however many table
    views may bind to it. If the model object doesn't have access to the
    array that contains it, then all this naturally won't work.

    António

    ----------------------------------------------------
    It isn't so important to do great things,
    as to do what you do with great love.
    ----------------------------------------------------
  • On 30 Aug 2007, at 02:30, Steven W Riggins wrote:

    >> I'm not sure if follow this. How so? The listindex is just a
    >> property of the model object, to which binding is 'legal' afaik.
    >
    > Your data could be in one view sorted ascending, at which object at
    > 1 is 1, and in a second view sorted descending, where object at 1
    > is n.

    Yes, that's true. What I showed is actually not simple line numbers,
    but the order of the objects in the array. In my app those two happen
    to always be in sync, since sorting the table view sorts the master
    array. But if sorting a table view doesn't sort the underlying master
    array then, even if you have only one table view, this technique
    won't show the result's you're after. Apologies for the mixup and
    lack of clarity.

    The following however will show proper line numbers:

    1. Create an NSTableView subclass:

    @interface ANLineNumberTableView : NSTableView {
    unsigned _lineNumber;
    }

    - (unsigned)lineNumber;

    @end

    @implementation ANLineNumberTableView

    - (unsigned)lineNumber
    {
    unsigned result = ++_lineNumber; // increment each time we are
    asked, which is once per row
    if (_lineNumber == [self numberOfRows]) // when at the last row we
    ned to reset the line number
      _lineNumber = 0;
    return result;
    }

    @end

    2. Bind the desired table view's column to its table view's
    lineNumber property.

    I created a little test project and it works a treat. The project
    also shows how to sort numbers in strings numerically (rather then
    alphabetically). To find the project take a break here: http://
    web.mac.com/antonionunes/

    If this latest code still is offensive do let me know. :-)

    António

    ----------------------------------------------------
    There is a world of difference between
    searching for happiness and choosing
    to be happy.
    ----------------------------------------------------
  • On 30/08/2007, at 9:14 PM, Antonio Nunes wrote:

    > The following however will show proper line numbers:
    >
    > 1. Create an NSTableView subclass:
    >
    > @interface ANLineNumberTableView : NSTableView {
    > unsigned _lineNumber;
    > }
    >
    > - (unsigned)lineNumber;
    >
    > @end
    >
    > @implementation ANLineNumberTableView
    >
    > - (unsigned)lineNumber
    > {
    > unsigned result = ++_lineNumber; // increment each time we are
    > asked, which is once per row
    > if (_lineNumber == [self numberOfRows]) // when at the last row we
    > ned to reset the line number
    > _lineNumber = 0;
    > return result;
    > }
    >
    > @end
    >
    > 2. Bind the desired table view's column to its table view's
    > lineNumber property.
    >
    > I created a little test project and it works a treat. The project
    > also shows how to sort numbers in strings numerically (rather then
    > alphabetically). To find the project take a break here: http://
    > web.mac.com/antonionunes/
    >
    > If this latest code still is offensive do let me know. :-)

    This approach doesn't look good to me. You're relying on an
    implementation detail that may change in future and it wouldn't
    surprise me if there were some circumstances where the approach above
    doesn't work.

    - Chris
  • On 30 Aug 2007, at 12:48, Chris Suter wrote:

    >> 1. Create an NSTableView subclass:
    >>
    >> @interface ANLineNumberTableView : NSTableView {
    >> unsigned _lineNumber;
    >> }
    >>
    >> - (unsigned)lineNumber;
    >>
    >> @end
    >>
    >> @implementation ANLineNumberTableView
    >>
    >> - (unsigned)lineNumber
    >> {
    >> unsigned result = ++_lineNumber; // increment each time we are
    >> asked, which is once per row
    >> if (_lineNumber == [self numberOfRows]) // when at the last row
    >> we ned to reset the line number
    >> _lineNumber = 0;
    >> return result;
    >> }
    >>
    >> @end
    >>
    >> 2. Bind the desired table view's column to its table view's
    >> lineNumber property.
    >>
    >> I created a little test project and it works a treat. The project
    >> also shows how to sort numbers in strings numerically (rather then
    >> alphabetically). To find the project take a break here: http://
    >> web.mac.com/antonionunes/
    >>
    >> If this latest code still is offensive do let me know. :-)
    >
    > This approach doesn't look good to me. You're relying on an
    > implementation detail that may change in future and it wouldn't
    > surprise me if there were some circumstances where the approach
    > above doesn't work.

    Fair enough. The latter had occurred to me, but I couldn't think
    offhand of an occasion where this would fail. Can you?
    As for relying on an implementation detail that may change: do you
    mean trusting that the column will get each cell's contents
    sequentially starting from the first row? If so, I guess you're
    right. Sigh. Not sturdy enough. My bad.

    All right then. No more trying to use bindings to get the row number
    of a table column. Back to data sources.

    Cheers,
    António

    ----------------------------------------------------
    The is nothing as strong as real gentleness, and
    there is nothing as gentle as real strength.
    ----------------------------------------------------
  • I implemented your approach for now and it works.  However, isn't there
    any better way to bind the column directly to the enclosing TableView?
    Using your approach, I'm going through my document object just to make the
    connection.  What happens if I want a second instance of the (nib) view for
    the same document?  Will the column references automatically get updated to
    the active window?

        Also, this is sort of a self-synchronizing approach to the enumeration,
    which is probably ok, assuming the table iterates all the rows each time.

    > Yes, that's true. What I showed is actually not simple line numbers,
    > but the order of the objects in the array. In my app those two happen
    > to always be in sync, since sorting the table view sorts the master
    > array. But if sorting a table view doesn't sort the underlying master
    > array then, even if you have only one table view, this technique
    > won't show the result's you're after. Apologies for the mixup and
    > lack of clarity.
    >
    > The following however will show proper line numbers:
    ...........
    >
  • On 31/08/2007, at 12:31 PM, Gordon Apple wrote:

    > I implemented your approach for now and it works.  However,
    > isn't there
    > any better way to bind the column directly to the enclosing TableView?
    > Using your approach, I'm going through my document object just to
    > make the
    > connection.  What happens if I want a second instance of the (nib)
    > view for
    > the same document?  Will the column references automatically get
    > updated to
    > the active window?
    >
    > Also, this is sort of a self-synchronizing approach to the
    > enumeration,
    > which is probably ok, assuming the table iterates all the rows each
    > time.

    Please read and take note of all earlier responses to your question.

    The approach you're following is not a good one and if it isn't
    already broken, it could get broken in future.

    The best solution has been given to you and should be simple to
    implement: use a datasource for that particular column. Apparently
    NSTableView works fine with both bindings and a datasource at the
    same time (although I've never tried it).

    - Chris
  • Thanks for all the responses.  I plan to do that, but I just wanted to
    see if that approach would work for now and it did.  For the moment, I'm
    going to focus getting drag and drop working in my tables.  (For the outline
    and browser view, I'll wait for the tree controller DnD support promised in
    10.5.)

    > Please read and take note of all earlier responses to your question.
    >
    > The approach you're following is not a good one and if it isn't
    > already broken, it could get broken in future.
    >
    > The best solution has been given to you and should be simple to
    > implement: use a datasource for that particular column. Apparently
    > NSTableView works fine with both bindings and a datasource at the
    > same time (although I've never tried it).
previous month august 2007 next month
MTWTFSS
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
Go to today