簡體   English   中英

基於視圖的NSTableView編輯

[英]View based NSTableView editing

我不確定我做錯了什么。 由於我找不到任何關於此的任何其他問題(甚至文檔),似乎通常對其他人沒有問題。

我只是想嘗試使用基於NSTableView的視圖來支持編輯它的內容。 即應用程序顯示帶有一列和多行的NSTableView,其中包含帶有一些內容的NSTextField。 我希望能夠(雙)單擊一個單元格並編輯單元格的內容。 所以基本上是基於NSTableView的單元格的正常行為,其中實現了tableView:setObjectValue:forTableColumn:row:方法。

我分析了Apple的TableViewPlayground示例代碼中的Complex TableView示例(支持編輯單元格內容),但我找不到啟用編輯的設置/代碼/開關。

這是一個簡單的示例項目(Xcode 6.1.1,SDK 10.10,基於故事板):

標題:

#import <Cocoa/Cocoa.h>

@interface ViewController : NSViewController

@property (weak) IBOutlet NSTableView *tableView;

@end

執行:

#import "ViewController.h"

@implementation ViewController
{
    NSMutableArray* _content;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    _content = [NSMutableArray array];

    for(NSInteger i = 0; i<10; i++) {
        [_content addObject:[NSString stringWithFormat:@"Item %ld", i]];
    }
}

#pragma mark - NSTableViewDataSource
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
    return _content.count;
}

#pragma mark - NSTableViewDelegate
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    NSTableCellView* cell = [tableView makeViewWithIdentifier:@"CellView" owner:self];
    cell.textField.stringValue = _content[row];
    return cell;
}

- (IBAction)endEditingText:(id)sender {
    NSInteger row = [_tableView rowForView:sender];
    if (row != -1) {
        _content[row] = [sender stringValue];
    }
}
@end

故事板文件如下所示: 故事板

表視圖的數據源和委托設置為視圖控制器。 運行此應用程序時,表視圖顯示10個測試行,但無法編輯其中一行。

這是為什么? 我在這里想念的是什么?

我仔細檢查了NSTableView的所有屬性(及其內容)與Apple的TableViewPlayground示例中的相同。 經過幾個小時的搜索文檔和互聯網有用的提示沒有任何成功,我有點沮喪。 您在基於視圖的NSTableViews上找到的所有內容都是不可編輯的樣本,或者是關於可編輯內容的非常模糊的信息。 當然,在可編輯的基於單元格的NSTableViews上有大量的信息,文檔和示例......

我的示例項目的zip可以在這里下載: TableTest.zip

即使編輯基於NSTableView的視圖的所有部分都存在於問題和答案中,我仍然無法將它們整合在一起。 以下演示使用Xcode 6.3.2在Swift中進行,但對於Objective-C cavemen / womens應該很容易理解。 最后是一個完整的代碼清單。

我們從這里開始:

NSTableViewDataSource協議參考

設置值

- tableView:setObjectValue:forTableColumn:row:

 Swift: optional func tableView(_ aTableView: NSTableView, setObjectValue anObject: AnyObject?, forTableColumn aTableColumn: NSTableColumn?, row rowIndex: Int) Objective-C: - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex 

討論 :此方法適用於基於單元格的表視圖,不能與基於視圖的表視圖一起使用。 在基於視圖的表中,使用target / action設置視圖單元格中的每個項目。

如果你像我一樣,你搜索了NSTableViewDelegate和NSTableViewDataSource協議,尋找某種編輯方法。 但是,上面引用的討論告訴你事情要簡單得多。

1)如果你在Xcode中查看TableView的文檔大綱 ,你會看到如下內容:

在此輸入圖像描述

TableView中的單元格由Table Cell View 單元格包含一些項目,默認情況下,其中一個項目是NSTextField。 但是文檔大綱中的NSTextField在哪里?! 好吧,文檔大綱中的控件有一個圖標,看起來就像名字旁邊的滑塊。 看一看。 在單元格內部,您會看到旁邊有滑塊圖標的東西。 並且,如果您在文檔大綱中選擇該行,然后打開Identity Inspector,您將看到它是NSTextField:

在此輸入圖像描述

您可以認為這只是一個普通的舊NSTextField。

實現NSTableViewDataSource協議方法時:

import Cocoa

class MainWindowController: NSWindowController,
                            NSTableViewDataSource {
    ...
    ...
    var items: [String] = []  //The data source: an array of String's
    ...
    ...

    // MARK: NSTableViewDataSource protocol methods

    func numberOfRowsInTableView(tableView: NSTableView) -> Int {
        return items.count
    }

    func tableView(tableView: NSTableView,
                   objectValueForTableColumn tableColumn: NSTableColumn?,
                   row: Int) -> AnyObject? {
        return items[row]
    }

}

.. TableView獲取第二個方法返回的值,並將其分配給外部Table Cell View名為objectValue的屬性 - 換句話說,TableView不使用返回值來設置NSTextField(即內部Table View Cell )。 這意味着您的數據源項目不會顯示在TableView中,因為NSTextField是顯示項目的內容。 要設置NSTextField的值,需要將NSTextField的value連接或綁定到objectValue屬性。 您可以在Bindings Inspector中執行此操作:

警告:確保在選擇要綁定的對象之前,不要選中“ Bind to復選框。 如果先選中該復選框,則會在文檔大綱中插入一個對象,如果您沒有注意到,則在運行程序時會出現錯誤。 如果您不小心首先檢查“ Bind to復選框,請確保刪除文檔大綱中自動添加的對象。 Xcode為添加的對象創建一個單獨的部分,因此很容易在文檔大綱中找到它。

在此輸入圖像描述

2)回溯片刻,您可能熟悉將按鈕連接到動作方法,此后如果單擊按鈕, 動作方法將執行。 另一方面,使用NSTextField,您通常會聲明一個IBOutlet,然后使用它來獲取或設置NSTextField的stringValue

但是,NSTextField也可以觸發執行操作方法。 什??! 但你不能像按鈕一樣點擊NSTextfield! 然而,NSTextField有一個觸發器,就像一個按鈕單擊,這將導致執行一個動作方法,觸發器是: 完成編輯NSTextField NSTextField如何知道您何時完成編輯? 有兩種方法:

  1. 你點擊Return。

  2. 你點擊其他一些控件。

您可以在“屬性”檢查器中選擇觸發器:

在此輸入圖像描述

3)正如@Paul Patterson在他的回答中所示,您需要做的下一件事是在屬性檢查器中將NSTextField的Behavior設置為可編輯

4)然后將NSTextField連接到要執行的操作方法。 如果您還沒有使用以下技巧將控件連接到操作方法,那么您應該嘗試一下:

在Project Navigator中選擇.xib文件,以便顯示窗口及其控件。 然后單擊Assistant Editor(最右側Xcode窗口頂部的two_interlocking_rings圖標) - 將顯示您的Controller文件(如果顯示了其他文件,則使用跳轉欄導航到您的Controller文件) 。 然后按住Control鍵並從NSTextField(在文檔大綱中)拖動到您要在其中創建操作方法的Controller文件中的位置:

在此輸入圖像描述

當您發布時,您將看到此彈出窗口:

在此輸入圖像描述

如果輸入的信息與顯示的信息相同,則會在文件中輸入以下代碼:

@IBAction func onEnterInTextField(sender: NSTextField) {

}

並且......已經完成了NSTextField和action方法之間的連接。 (您也可以使用這些步驟創建和連接IBOutlet。)

5)在action方法中,您可以從TableView獲取當前選定的行,即剛剛編輯過的行:

@IBAction func onEnterInTextField(sender: NSTextField) {    
    let selectedRowNumber = tableView.selectedRow  //tableView is an IBOutlet connected to the NSTableView

}

然后我對如何在TableView中獲取所選行的文本感到困惑,然后回到我通過TableView和協議方法查看的文檔。 但是,我們都知道如何獲取NSTextField的stringValue,對吧? 發件人是您正在編輯的NSTextField:

@IBAction func onEnterInTextField(sender: NSTextField) {
    let selectedRowNumber = tableView.selectedRow  //My Controller has  an IBOutlet property named tableView which is connected to the TableView 

    if selectedRowNumber != -1 {  //-1 is returned when no row is selected in the TableView
        items[selectedRowNumber] = sender.stringValue  //items is the data source, which is an array of Strings to be displayed in the TableView
    }

}

如果未在數據源中插入新值,則下次TableView需要顯示行時,將再次顯示原始值,覆蓋已編輯的更改。 請記住,TableView從數據源檢索值 - 而不是NSTextField。 然后NSTextField顯示TableView分配給單元格的objectValue屬性的任何值。

最后一件事 :我收到一條警告說我無法將NSTextField連接到類中的動作,如果該類不是TableView的委托....所以我將TableView的委托出口連接到File的所有者:

在此輸入圖像描述

我之前已經將File的Owner設置為我的Controller(= MainWindowController),所以在我建立連接后,MainWindowController(包含NSTextField的action方法)成為TableView的委托,警告消失了。

隨機提示:

1)我發現開始編輯NSTextField最簡單的方法是在TableView中選擇一行,然后點擊Return。

2)默認情況下,NSTableView有兩列。 如果選擇文檔大綱中的一列,然后單擊鍵盤上的Delete,則可以創建一個列表 - 但TableView仍然顯示列分隔符,因此看起來仍然有兩列。 要刪除列分隔符,請在文檔大綱中選擇“邊框Bordered Scroll View - Table View ”,然后拖動其中一個角來調整TableView的大小 - 單個列將立即調整大小以占用所有可用空間。

感謝步驟#1和#2,以及隨機提示#2:OS X的可可編程(2015年第5版)。

完整代碼清單:

//
//  MainWindowController.swift
//  ToDo
//

//import Foundation
import Cocoa

class MainWindowController: NSWindowController,
                            NSTableViewDataSource {

    //@IBOutlet var window: NSWindow? -- inherited from NSWindowController
    @IBOutlet weak var textField: NSTextField!
    @IBOutlet weak var tableView: NSTableView!

    var items: [String] = []  //The data source: an array of String's

    override var windowNibName: String {
        return "MainWindow"
    }

    @IBAction func onclickAddButton(sender: NSButton) {
        items.append(textField.stringValue)
        tableView.reloadData()  //Displays the new item in the TableView

    }

    @IBAction func onEnterInTextField(sender: NSTextField) {
        let selectedRowNumber = tableView.selectedRow

        if selectedRowNumber != -1 {
            items[selectedRowNumber] = sender.stringValue
        }
    }


    // MARK: NSTableViewDataSource protocol methods

    func numberOfRowsInTableView(tableView: NSTableView) -> Int {
        return items.count
    }

    func tableView(tableView: NSTableView,
                   objectValueForTableColumn tableColumn: NSTableColumn?,
                   row: Int) -> AnyObject? {
        return items[row]
    }

 }

Connections Inspector顯示File的Owner(= MainWindowController)的所有連接:

在此輸入圖像描述

默認情況下,每個單元格( NSTableCellView實例)都有一個NSTextField 當您編輯單元格時,您實際編輯的是此文本字段。 Interface Builder使此文本字段不可編輯:

在此輸入圖像描述

您需要做的就是將“ 行為”彈出窗口設置為“ Editable 現在你可以打回或單個鍵並單擊編輯文本字段。

只是對已接受的答案進行更正 - 您應該使用tableView.row(對於:NSView)和tableView.column(對於:NSView)獲取行和列。其他方法可能不可靠。

@IBAction func textEdited(_ sender: Any) {
        if let textField = sender as? NSTextField {

            let row = self.tableView.row(for: sender as! NSView)
            let col = self.tableView.column(for: sender as! NSView)
            self.data[row][col] = textField.stringValue

            print("\(row), \(col), \(textField.stringValue)")

            print("\(data)")
        }
    }

暫無
暫無

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

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