Disabling edit on single-click in view-based NSTableView?

Hello,


I'm coming across some bizarre behaviour in a view-based NSTableView and I can't work out what's causing it: single-clicking to select a row causes the row to start editing after a second. This happens only in two of my table views (one using Auto-Layout, the other not, so that's not a factor); I'm not seeing this behaviour in any of my other view-based table views that allow editing, even with apparently the same settings.


I'm aware that standard behaviour is that if you select a row, and then click on it again, it will start editing. But also, I thought that setting up a doubleAction on a table view prevented this behaviour. And yet, one of my table views with this behaviour has a double action on it (to start editing on double-click). Moreover, editing isn't starting on a row that you click on which is already selected; editing is beginning when you simply click on an un-selected row to select it. After a slight delay, it begins editing.


I tried subclassing NSTextField and setting a breakpoint -becomeFirstResponder to see what was triggering the edit. This wasn't very informative - it just tells me that private Apple methods are starting the edit after a delay:


[NSTableRowData _delayMakeFirstResponder]


I've been comparing the table against others that don't have the problem, and I can't find any differences: I'm calling the same methods in code, and setting them up the same in IB. I even went through line-by-line in the .xib file comparing two tables, but the XML was much the same for both, and experimenting to make them exactly the same did not help. I also deleted the table view in IB and rebuilt it - it has the same problem.


The behaviour is hugely annoying - has anybody else experienced this, and does anyone know how to fix it? (I'm aware that I haven't provided an awful lot to go on, but there is nothing special about these tables compared to other tables that work as expected; they are both populated an NSArrayController, but all options for the tables and array controlles are the same as other tables.)


Many thanks,

Keith

Post not yet marked as solved Up vote post of KeithB Down vote post of KeithB
3.3k views

Replies

Update: Weirdly, this seems to be *caused* by -setDoubleAction:. If I comment that out, then selection doesn't cause editing to begin. Even so, this only happens in two tables, as I say - the other tables have -setDoubleAction: set up an action on them, and they do not exhibit this strange behaviour, so I have no idea what is going on. I can just override -mouseDown: in my NSTableView subclass and start editing on the text field for the NSTableCellView at the mouse point if clickCount==2, which works fine and fixes the issue, but I'd love to understand the underlying cause...

Do you use a trackpad? Do you have it configured that a tap does a click? (That is, you can click without actually pushing the trackpad down.) I've encountered a bug where using that feature caused a table view to start editing the row on first "click".

Unfortunately not, no - I'm using a regular mouse, left-clicking. And the problem is only exhibited when -setDoubleAction: is on, and only in two tables - others are working fine, as I say. It's very bizarre.

I managed to reproduce this in a test project, so I'm now wondering if this is intended behaviour and all of my other table views are somehow preventing it becuase of the various custom classes I use (even though I'm using the same custom classes in my app for the tables affected). Anyway, here's a sample project showing the issue if anyone has time to take a look:


http://literatureandlatte.com/misc/TableEditBugTest.zip


Simply download, build and run, then click into the rows. Clicking on the text area of a row causes editing to start immediately, regardless of whether row was already selected or not; clicking to the right of the text causes expected behaviour, with the row just being selected. This behaviour only occurs when -setDoubleAction: is set and the text field in the table cell is set to be editable.

I just posted a reply with a sample project showing the issue, but of course, now that posts with links in them are moderated, that may not show up for a day or so. But essentially, it seems easy to reproduce this behaviour in a sample project as follows:


1. Create a view-based NSTableView and hook it up to an NSArrayController (arrangedObjects and selectionIndexes bound to the array controller, the objectValue.key of the cell view text field bound to the cell view etc).


2. Set the cell view's text field to be editable.


3. In code, set the content of the array controller to an array of dictionaries simply containing e.g. @[@{"key": @"Foo"}, @{@"key": @"Bar"}] (but with a mutable array and dictionaries, of course).


4. Set a -doubleAction on the table view (a dummy action will do).


Once you've done all of the above, simply clicking on in the text area of a row causes it to be edited (after a slight delay) without needing to select it first and then click again. (2) and (4) are clearly the key culprits here. Back with cell-based views, I think that a column had to be set not to be editable in order for doubleAction to work properly. But that was fine, because (a) you didn't need to use -doubleAction: to get editing to work on double-clicking - that was standard behaviour; (b) if you did need to use -setDoubleAction:, -editColumn:... would work regardless of whether or not the column was set to be editable. I'm not sure why you would ever want editing to kick in with a single-click on a row that hasn't even been selected.


So I'm now thinking that:


A. This is either intended behaviour or a bug in AppKit. Presumably the latter - I can't see why it would be intended behaviour. My expectation would be that edit-after-delay-after-click would only happen with an already selected row, not one you have just clicked on to select. (Alternatively, I may well just be missing something stupidly obvious, in which case I welcome someone pointing out my ineptitude!)


B. Something in my other table views is preventing this behaviour somehow (which is fortunate).


Many thanks,

Keith

My solution to this problem has (for a long time) been to make the columns of the table not editable. But, in my case, I'm using the double click action as a means of getting to an editor to edit the whole row, as the row is only a very limited representation of some aspects of the underlying object.


Rod

Thanks for the reply. Making the columns uneditable makes no difference, I'm afraid. Are you using cell-based tables by any chance? I used to take that approach with cell-based tables, but with view-based tables you disable editing at the text field level. But if the text fields aren't set to editable, then click-after-delay doesn't work (for when you want to click and then click again instead of triggering the double-click action).

Okay, I discovered the difference between the table views that weren't having this issue and the ones that were: the ones that are fine implement drag-and-drop via a data source. So, the work around is to set a data source on any table views that have a doubleAction set, and implement -tableView:pasteboardWriterForRow:, returning nil if you don't want to write anything. I've reported the issue as #21562075, as this is clearly an AppKit bug with view-based tables using doubleAction.

I'm here just to note that I also noticed this behavior. As soon as I set "doubleAction" on NSOutlineView, the cell start editing after first tap. This is macOS 11 so I assume if it hasn't been fixed by now, we have to deal with it.

I'm still having this problem in an outline table with no action or double action and with an implementation of outlineView:pasteboardWriterForItem:.