私もこれに悩まされたので、サンプル プロジェクトを作成して GitHub にアップロードしました。
@ben-rhayader が指摘したように、フィールド エディターをヘッダー ビュー セルの上に配置することがすべてです。
ダブルクリックの扱い
以下は、Swift についてすでにわかっていることです。
ウィンドウ コントローラ / カスタム テーブル ビュー コントローラ
ビュー コントローラーの興味深い部分は、ダブルクリックでヘッダーを編集することです。それを実現するために、
TableWindowController
(またはビュー コントローラー) インスタンスをオブジェクトとして Nib に配置し、
@IBAction func tableViewDoubleClick(sender: NSTableView)
または同様のものを追加し、
NSTableView
のdoubleAction
メソッドを に接続しtableViewDoubleClick
ます。
セルの編集は簡単です。列ヘッダーの編集はそれほど多くありません。
- ヘッダー行の行値は -1 です
- フィールド エディターを配置するには、列ヘッダー フレームとフィールド エディター自体が必要です。
結果の一部:
extension TableWindowController {
@IBAction func tableViewDoubleClick(sender: NSTableView) {
let column = sender.clickedColumn
let row = sender.clickedRow
guard column > -1 else { return }
if row == -1 {
editColumnHeader(tableView: sender, column: column)
return
}
editCell(tableView: sender, column: column, row: row)
}
private func editColumnHeader(tableView tableView: NSTableView, column: Int) {
guard column > -1,
let tableColumn = tableView.tableColumn(column: column),
headerView = tableView.headerView as? TableHeaderView,
headerCell = tableColumn.headerCell as? TableHeaderCell,
fieldEditor = fieldEditor(object: headerView)
else { return }
headerCell.edit(
fieldEditor: fieldEditor,
frame: headerView.paddedHeaderRect(column: column),
headerView: headerView)
}
private func editCell(tableView tableView: NSTableView, column: Int, row: Int) {
guard row > -1 && column > -1,
let view = tableView.viewAtColumn(column, row: row, makeIfNecessary: true) as? NSTableCellView
else { return }
view.textField?.selectText(self)
}
/// Convenience accessor to the `window`s field editor.
func fieldEditor(object object: AnyObject?) -> NSText? {
return self.window?.fieldEditor(true, forObject: object)
}
}
カスタム ヘッダー ビューとヘッダー ビュー セル
フィールド エディタを適切に配置するのは少し手間がかかります。NSTableHeaderView
私はそれをサブクラスに入れました:
class TableHeaderView: NSTableHeaderView {
/// Trial and error result of the text frame that fits.
struct Padding {
static let Vertical: CGFloat = 4
static let Right: CGFloat = 1
}
/// By default, the field editor will be very high and thus look weird.
/// This scales the header rect down a bit so the field editor is put
/// truly in place.
func paddedHeaderRect(column column: Int) -> NSRect {
let paddedVertical = CGRectInset(self.headerRectOfColumn(column), 0, Padding.Vertical)
let paddedRight = CGRect(
origin: paddedVertical.origin,
size: CGSize(width: paddedVertical.width - Padding.Right, height: paddedVertical.height))
return paddedRight
}
}
これにより、フィールド エディターの配置が処理されます。上記のダブルクリックハンドラーから使用します。
class TableHeaderCell: NSTableHeaderCell, NSTextViewDelegate {
func edit(fieldEditor fieldEditor: NSText, frame: NSRect, headerView: NSView) {
let endOfText = (self.stringValue as NSString).length
self.highlighted = true
self.selectWithFrame(frame,
inView: headerView,
editor: fieldEditor,
delegate: self,
start: endOfText,
length: 0)
fieldEditor.backgroundColor = NSColor.whiteColor()
fieldEditor.drawsBackground = true
}
func textDidEndEditing(notification: NSNotification) {
guard let editor = notification.object as? NSText else { return }
self.title = editor.string ?? ""
self.highlighted = false
self.endEditing(editor)
}
}
ユーザーが別のヘッダーセルをダブルクリックしたときに「編集を終了」する方法は?
問題: ユーザーが別のヘッダー セルをダブルクリックすると、フィールド エディターが再利用され、位置が変更されるだけです。textDidEndEditing
呼び出されません。新しい値は保存されません。
@triple.s と @boyfarrell はこれについて議論しましたが、コードはありません。フィールド エディターがいつ変更されるかを知る最も簡単な方法は、フィールド エディターの構成をハイジャックしてendEditing
手動で呼び出すことです。
class HeaderFieldEditor: NSTextView {
func switchEditingTarget() {
guard let cell = self.delegate as? NSCell else { return }
cell.endEditing(self)
}
}
必要に応じて、このカスタム フィールド エディターを使用します。
class TableWindowController: NSWindowDelegate {
func windowWillReturnFieldEditor(sender: NSWindow, toObject client: AnyObject?) -> AnyObject? {
// Return default field editor for everything not in the header.
guard client is TableHeaderView else { return nil }
// Comment out this line to see what happens by default: the old header
// is not deselected.
headerFieldEditor.switchEditingTarget()
return headerFieldEditor
}
lazy var headerFieldEditor: HeaderFieldEditor = {
let editor = HeaderFieldEditor()
editor.fieldEditor = true
return editor
}()
}
魅力のように機能します。
GitHub のプロジェクト: https://github.com/DivineDominion/Editable-NSTableView-Header