Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Double-click editing of NSTableView columns headers

Is it possible to change the names of NSTableView columns by double clicking on the columns headers? Any suggestions on the best way to do this.

I am trying:

  1. Set the double action of the table view to call a custom method on the double click
  2. Try and edit the NSTableHeaderCell instance by calling editWithFrame:inView:editor:delegate:event:.

I'm not entirely sure why this distorts the text, but when you double click the header it makes the text look like this, no field editor appears,

editWithFrame:inView:editor:delegate:event: on an NSTableHeaderCell

In the AppDelegate,

-(void)awakeFromNib
{
    ...
    [_tableView setDoubleAction:@selector(doubleClickInTableView:)];
    ...
}

-(void) doubleClickInTableView:(id)sender
{
    NSInteger row = [_tableView clickedRow];
    NSInteger column = [_tableView clickedColumn];
    if(row == -1){
        /* Want to edit the column header on double-click */
        NSTableColumn *tableColumn = [[_tableView tableColumns] objectAtIndex:column];
        NSTableHeaderView *headerView = [_tableView headerView];
        NSTableHeaderCell *headerCell = [tableColumn headerCell];
        NSRect cellFrame = [headerView headerRectOfColumn:column];
        NSText * fieldEditor = [[headerView window] fieldEditor:YES forObject:nil];
        [headerCell editWithFrame:cellFrame inView:headerView editor:fieldEditor delegate:headerCell event:nil];
    }

}
like image 861
Daniel Farrell Avatar asked Jan 31 '13 14:01

Daniel Farrell


People also ask

What are the NSTableView row edges constants?

These constants define table row edges on which row actions are attached. They are used by the tableView:rowActionsForRow:edge: delegate method. Posted whenever a column is moved by user action in an NSTableView object. Posted whenever a column is resized in an NSTableView object.

What is a nstableviewdelegate?

For example, the delegate supports table column management, type-to-select functionality, row selection and editing, custom tracking, and custom views for individual columns and rows. To learn more about the table view delegate, see NSTableViewDelegate.

How do I customize a table view without subclassing NSTableView?

To learn about the methods that an NSTableView object uses to provide and access the contents of its data source object, see NSTableViewDataSource. To customize a table view’s behavior without subclassing NSTableView, use the methods defined by the NSTableViewDelegate protocol.

Can you use NSView instead of cells in a table view?

Table views are displayed in scroll views. Beginning with macOS v10.7, you can use NSView objects (most commonly customized NSTableCellView objects) instead of cells for specifying rows and columns. You can still use NSCell objects for each row and column item if you prefer.


1 Answers

it seems doable
what you see in your screenshot is the window's field editor overlaying your cell's textfield
the editor has a transparent background so that's why it's messed up

so here's the deal :

you will need to have your own NSTableHeaderCell subclass to act as the field editor's delegate :

@interface NBETableHeaderCell () <NSTextViewDelegate>
@end

@implementation NBETableHeaderCell

- (void)textDidEndEditing:(NSNotification *)notification
{
    NSTextView *editor = notification.object;
    // Update the title, kill the focus ring, end editing
    [self setTitle:editor.string];
    [self setHighlighted:NO];
    [self endEditing:editor];
}

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    if([self isHighlighted])
    {
        [self drawFocusRingMaskWithFrame:cellFrame inView:controlView.superview];
    }

    [super drawWithFrame:cellFrame inView:controlView];
}

- (void)drawFocusRingMaskWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    [controlView lockFocus];
    NSSetFocusRingStyle(NSFocusRingOnly);
    [[NSBezierPath bezierPathWithRect:cellFrame] fill];
    [controlView unlockFocus];
}

@end

in the app delegate's awakeFromNib don't forget to set the NSTableHeaderCell to Editable !

- (void)awakeFromNib
{
    NSTableColumn *newCol = [[NSTableColumn alloc] initWithIdentifier:@"whatever"];

    NBETableHeaderCell *hc = [[NBETableHeaderCell alloc] initTextCell:@"Default header text"];
    [hc setEditable:YES];
    [hc setUsesSingleLineMode:YES];
    [hc setScrollable:NO];
    [hc setLineBreakMode:NSLineBreakByTruncatingTail];
    [newCol setHeaderCell:hc];

    [self.tableView addTableColumn:newCol];
    [self.tableView setDoubleAction:@selector(doubleClickInTableView:)];
}

for the rest, you were nearly there
after calling selectWithFrame, we customize the editor to have a nice white opaque background,
so that we don't see the textview beneath it
as for the focus ring : it is the cell's job,
we just set the cell in highlighted state so it knows it has to draw the ring now

- (void)doubleClickInTableView:(id)sender
{
    NSInteger row = [_tableView clickedRow];
    NSInteger column = [_tableView clickedColumn];

    if(row == -1&& column >= 0)
    {
        NSTableColumn *tableColumn = [[_tableView tableColumns] objectAtIndex:column];
        NSTableHeaderView *headerView = [_tableView headerView];
        NBETableHeaderCell *headerCell = [tableColumn headerCell];

        // cellEditor is basically a unique NSTextView shared by the window
        // that adjusts its style to the field calling him
        // it stands above the text field's view giving the illusion that you are editing it
        // and if it has no background you will see the editor's NSTextView overlaying the TextField
        // wich is why you have that nasty bold text effect in your screenshot
        id cellEditor = [self.window fieldEditor:YES forObject:self.tableView];

        [headerCell setHighlighted:YES];
        [headerCell selectWithFrame:[headerView headerRectOfColumn:column]
                             inView:headerView
                             editor:cellEditor
                           delegate:headerCell
                              start:0
                             length:headerCell.stringValue.length];

        [cellEditor setBackgroundColor:[NSColor whiteColor]];
        [cellEditor setDrawsBackground:YES];
    }
}

some more info about the field editor here : http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/WinPanel/Tasks/UsingWindowFieldEditor.html

the only thing missing now to make it complete is that the field editor's frame won't update if you resize the cell while editing…

like image 164
Nightbirdsevolve Avatar answered Oct 30 '22 10:10

Nightbirdsevolve