9

列ヘッダーをダブルクリックして NSTableView 列の名前を変更することはできますか? これを行うための最良の方法に関する提案。

やっています:

  1. テーブルビューのダブルアクションを設定して、ダブルクリックでカスタムメソッドを呼び出します
  2. を呼び出して NSTableHeaderCell インスタンスを編集してみてくださいeditWithFrame:inView:editor:delegate:event:

これがテキストをゆがめる理由は完全にはわかりませんが、ヘッダーをダブルクリックすると、テキストは次のようになります。フィールド エディターは表示されません。

editWithFrame:inView:editor:delegate:event: NSTableHeaderCell で

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];
    }

}
4

4 に答える 4

8

スクリーンショットに表示されている
のは、ウィンドウのフィールドエディターがセルのテキストフィールドをオーバーレイしていることです
エディターの背景が透明であるため、めちゃくちゃになっています

だからここに契約があります:

フィールド エディターのデリゲートとして機能するには、独自の NSTableHeaderCell サブクラスが必要です。

@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

アプリ デリゲートの awakeFromNib で、NSTableHeaderCell を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:)];
}

残りの部分については、 selectWithFrame を呼び出した
、ほぼそこにいます。エディタをカスタマイズして、背景が白い不透明になるようにします。これにより、フォーカス リングのよう
にその下にテキストビューが表示されなく
なります。これはセルの仕事であり、
設定するだけです。強調表示された状態のセルで、今すぐリングを描画する必要があることを認識します

- (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];
    }
}

フィールドエディタに関する詳細情報: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/WinPanel/Tasks/UsingWindowFieldEditor.html

編集中にセルのサイズを変更すると、フィールド エディターのフレームが更新されないことだけが、今では完全に欠けています。

于 2013-02-13T21:18:21.870 に答える
3

私もこれに悩まされたので、サンプル プロジェクトを作成して GitHub にアップロードしました。

@ben-rhayader が指摘したように、フィールド エディターをヘッダー ビュー セルの上に配置することがすべてです。

ダブルクリックの扱い

以下は、Swift についてすでにわかっていることです。

ウィンドウ コントローラ / カスタム テーブル ビュー コントローラ

ビュー コントローラーの興味深い部分は、ダブルクリックでヘッダーを編集することです。それを実現するために、

  • TableWindowController(またはビュー コントローラー) インスタンスをオブジェクトとして Nib に配置し、
  • @IBAction func tableViewDoubleClick(sender: NSTableView)または同様のものを追加し、
  • NSTableViewdoubleActionメソッドを に接続し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

于 2016-04-11T15:48:31.220 に答える
1

@BenRhayader - このソリューションは、列ヘッダーのテキストを変更し、controlTextDidEndEditingデリゲートが呼び出されるようにタブを実行した場合にのみ機能します。しかし、ある列のヘッダー列のテキストを変更し、(タブアウトを実行する代わりに) 他の列をクリックすると、古いテキストが保持されます。つまり、新しいテキストが反映されません。これは、テキストを変更するロジックがcontrolTextDidEndEditing、タブ アウトが実行されたときにのみ呼び出される 内に記述されているためである可能性があります。

于 2013-07-05T05:12:54.417 に答える
0

あなたの質問はここで否定的に答えられました:NSTableView列ヘッダーを編集可能にする

于 2013-02-12T09:05:08.843 に答える