簡體   English   中英

雙擊編輯NSTableView列標題

[英]Double-click editing of NSTableView columns headers

是否可以通過雙擊列標題來更改NSTableView列的名稱? 有關最佳方法的任何建議。

我在嘗試:

  1. 設置表視圖的雙重操作以在雙擊時調用自定義方法
  2. 通過調用editWithFrame:inView:editor:delegate:event:嘗試編輯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];
    }

}

看起來可行
您在屏幕截圖中看到的是窗口的字段編輯器覆蓋您單元格的文本字段
編輯器有一個透明的背景,這就是為什么它搞砸了

所以這是交易:

您將需要擁有自己的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

在app delegate的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之后,我們自定義編輯器以獲得漂亮的白色不透明背景,
這樣我們就看不到它下面的textview了
至於焦點圈:這是細胞的工作,
我們只是將單元格設置為高亮顯示狀態,因此它知道它現在必須繪制環

- (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

現在唯一缺少的就是如果在編輯時調整單元格的大小,字段編輯器的框架將不會更新...

這也讓我感到煩惱,所以我創建了一個示例項目並將其上傳到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構造和手動調用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

你的問題在這里被否定了回答: 使NSTableView列標題可編輯

@BenRhayader - 此解決方案僅在我更改列標題文本並執行選項卡以便調用controlTextDidEndEditing委托時才起作用。 但是,如果我更改一列的標題列文本並單擊其他列(而不是執行制表符),則會保留舊文本,即新文本不會反映。 這可能是因為更改文本的邏輯寫在controlTextDidEndEditing ,只有在完成Tab鍵時才會調用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM