Пример NSOutlineView

Пожалуйста, не могли бы вы дать простой полный пример приложения Cocoa с NSOutlineView с представлением иерархических данных, не столь неоднозначным, как пример NSOutlineView и NSTreeController .

Спасибо!

Ответ 1

В этом примере используется простая двухслойная иерархия двух родителей Foo и Bar, у каждого из которых есть два дочерних элемента, Foox, Fooz и Barx, Barz соответственно, контурный вид является стандартным видом с двумя столбцами, а идентификатор второго столбца установлен равным "дети".

NSDictionary *firstParent = @{@"parent": @"Foo", @"children": @[@"Foox", @"Fooz"]};
NSDictionary *secondParent = @{@"parent": @"Bar", @"children": @[@"Barx", @"Barz"]};
NSArray *list = @[firstParent, secondParent];

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{        
    if ([item isKindOfClass:[NSDictionary class]]) {
        return YES;        
    }else {
        return NO;
    }
}

- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{    

    if (item == nil) { //item is nil when the outline view wants to inquire for root level items
        return [list count];                 
    }   

    if ([item isKindOfClass:[NSDictionary class]]) {
        return [[item objectForKey:@"children"] count];
    }

    return 0;
}

- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
{

    if (item == nil) { //item is nil when the outline view wants to inquire for root level items
        return [list objectAtIndex:index];                   
    }

    if ([item isKindOfClass:[NSDictionary class]]) {
        return [[item objectForKey:@"children"] objectAtIndex:index];
    }     

    return nil;
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)theColumn byItem:(id)item
{          

    if ([[theColumn identifier] isEqualToString:@"children"]) {
        if ([item isKindOfClass:[NSDictionary class]]) {
            return [NSString stringWithFormat:@"%i kids",[[item objectForKey:@"children"] count]];
        }  
        return item;
    }else{
        if ([item isKindOfClass:[NSDictionary class]]) {
            return [item objectForKey:@"parent"];                         
        }           
    }

    return nil;
}

screenshot

Ответ 2

NSOutlineView с использованием NSURL и Swift простой пример заполнения структуры каталогов

AppDelegate.swift

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {


    var mainWindowController: MainWindowController?

    func applicationDidFinishLaunching(aNotification: NSNotification) {
        // Insert code here to initialize your application
        let mainWindowController = MainWindowController()
        mainWindowController.showWindow(self)
        self.mainWindowController = mainWindowController

    }

    func applicationWillTerminate(aNotification: NSNotification) {
        // Insert code here to tear down your application
    }

    func applicationShouldTerminateAfterLastWindowClosed(sender: NSApplication) -> Bool {
        return true
    }
}

FileItem.swift

class FileItem {
    var url: NSURL!
    var parent: FileItem?
    var isLeaf:Bool = false
    static let fileManager = NSFileManager.defaultManager()
    static let requiredAttributes = [NSURLIsDirectoryKey]
    static let options: NSDirectoryEnumerationOptions = [.SkipsHiddenFiles, .SkipsPackageDescendants, .SkipsSubdirectoryDescendants]


    lazy var children: [FileItem]? = {
        if let enumerator = fileManager.enumeratorAtURL(self.url, includingPropertiesForKeys:FileItem.requiredAttributes, options: FileItem.options, errorHandler: nil) {

            var files = [FileItem]() 

            while let localURL = enumerator.nextObject() as? NSURL {
                do {
                    let properties = try localURL.resourceValuesForKeys(FileItem.requiredAttributes)
                    // check this
                    files.append(FileItem(url: localURL, parent: self, isLeaf: (properties[NSURLIsDirectoryKey] as! NSNumber).boolValue))
                } catch {
                    print("Error reading file attributes")
                }
            }
            return files
        }
        return nil
    }()

    init(url: NSURL, parent: FileItem?, isLeaf: Bool){
        self.url = url
        self.parent = parent
        self.isLeaf = isLeaf
    }

    var displayName: String {
        get {
            return self.url.lastPathComponent!
        }
    }

    var count: Int {
        return (self.children?.count)!
    }

    func childAtIndex(n: Int) -> FileItem? {
        return self.children![n]
    }
}

Я использую MainWindowController с xib удаленным предоставленным окном из делегата приложения и IBOutlet для окна

import Cocoa

class MainWindowController: NSWindowController {

    @IBOutlet weak var outline: NSOutlineView!
    private var rootItem: FileItem? = FileItem(url: NSURL(fileURLWithPath:"/"), parent: nil, isLeaf: true)

    override func windowDidLoad() {
        super.windowDidLoad()

        // Implement this method to handle any initialization after your window controller window has been loaded from its nib file.
    }

    override var windowNibName: String? {
        return "MainWindowController"
    }
}

//MARK: - NSOutlineViewDelegate
extension MainWindowController: NSOutlineViewDelegate {

    func outlineView(outlineView: NSOutlineView, viewForTableColumn tableColumn: NSTableColumn?, item: AnyObject) -> NSView? {
        let view = outline.makeViewWithIdentifier("TextCell", owner: self) as? NSTableCellView
        if let it = item as? FileItem {
            if let textField = view?.textField {
                textField.stringValue = it.displayName
            }
        } else {
            if let textField = view?.textField {
                textField.stringValue = self.rootItem!.displayName
            }
        }
        return view
    }
}

//MARK: - NSOutlineViewDataSource
extension MainWindowController: NSOutlineViewDataSource {

     func outlineView(outlineView: NSOutlineView, child index: Int, ofItem item: AnyObject?) -> AnyObject {
        if let it = item as? FileItem {
            return it.childAtIndex(index)!
        }
        return rootItem!
    }
    func outlineView(outlineView: NSOutlineView, numberOfChildrenOfItem item: AnyObject?) -> Int {
        if let it = item as? FileItem {
            return it.count
        }
        return 1
    }
    func outlineView(outlineView: NSOutlineView, isItemExpandable item: AnyObject) -> Bool {
        if let it = item as? FileItem {
            if it.count > 0 {
                return true
            }
        }
        return false
    }
}

Пример здесь OutlineView

Это модифицированная версия этого примера NSOutlineViewInSwift