swift 包含两个子项的大纲视图 children
swift outline view with two sub children
我在 macOS 上使用 swift 4,我有一个 NSOutlineView:
我从核心数据中获取数据。
结构:
- 实体人(与实体书的关系)
- 实体书
我对此结果的代码:
@IBOutlet weak var myOutlineView: NSOutlineView!
let context = (NSApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var people = [Person]()
override func viewWillAppear() {
requestPeople()
}
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
let view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: self) as? CustomCell
if let person = item as? Person {
// Show Person
} else if let book = item as? Book {
// Show Books
}
return view
}
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
if let person = item as? Person {
return person.books.count
}
return people.count
}
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
if let person = item as? Person {
return person.books[index]
}
return people[index]
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
if let person = item as? Person {
return person.books.count > 0
}
return false
}
func requestPeople() {
let request = NSFetchRequest<Person>(entityName: "Person")
do {
people = try context.fetch(request)
myOutlineView.reloadData()
} catch { print(error) }
}
现在我的问题是:
我想创建另一个大纲视图。
我的 Book 实体看起来像这样(属性):
- 名字
- 创建日期
我的新大纲视图应该采用这种结构:
+ Year
++ Month
+++ Bookname
但我不知道如何实现这个结构。
和我的第一个大纲视图不一样。
有人可以帮我吗?
=======
我想我已经为年份和月份创建了没有重复的数组。
为此,我尝试使用此函数来获取数据:
var year = [String]()
var month = [String]()
var books = [Book]()
func requestBooks() {
let request = NSFetchRequest<Book>(entityName: "Book")
do {
books = try context.fetch(request)
for x in 0 ...< books.count {
if !year.contains("\(Calendar.current.component(.year, from: books[x].creationDate))") {
year.append("\(Calendar.current.component(.year, from: books[x].creationDate))")
}
if !month.contains("\(Calendar.current.component(.month, from: books[x].creationDate))") {
month.append("\(Calendar.current.component(.month, from: books[x].creationDate))")
}
}
myOutlineView.reloadData()
} catch { print(error) }
}
当您的底层数据结构是分层的(即树结构)时,多级大纲更易于管理。
以下是如何为图书创建 "Tree" 节点 class 的示例:
class BookNode
{
// levels and relationships, from parent to children
enum Level { case Top, Year, Month, Book }
let subLevels:[Level:Level] = [ .Top:.Year, .Year:.Month, .Month:.Book ]
var label = "" // description and unique "key"
var level = Level.Top
var children : [BookNode] = []
var book : Book! = nil // .Book level will store the actual Book
// add book to hierarchy, auto-create intermediate levels
func add(_ book:Book)
{
var subLabel = ""
switch level
{
case .Top : subLabel = String(Calendar.current.component(.year, from:book.creationDate))
case .Year : subLabel = String(Calendar.current.component(.month, from:book.creationDate))
case .Month : subLabel = book.name
case .Book : self.book = book // last level stores the book
return // and has no children
}
// Add branch (.Year, .Month) or leaf (.Book) node as needed
var subNode:BookNode! = children.first{[=10=].label == subLabel}
if subNode == nil
{
subNode = BookNode()
subNode.level = subLevels[level]!
subNode.label = subLabel
children.append(subNode)
}
// keep adding recursively down to .Book level
subNode.add(book)
}
}
您的数据将存储在 BookNodes 的层次结构中,您可以从提取请求中加载它
(您可以像我一样对其进行预排序,或者将其留给 BookNode class)
var topNode = BookNode()
func requestBooks()
{
let request = NSFetchRequest<Book>(entityName: "Book")
do {
let books = try context.fetch(request)
topNode = BookNode()
for book in books.sorted(by:{[=11=].creationDate < .creationDate})
{
topNode.add(book)
}
}
}
有了这个,使用 BookNodes 作为大纲项目将很容易响应你的大纲协议:
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView?
{
let view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: self) as? CustomCell
let node = (item as? BookNode) ?? topNode
switch node.level
{
case .Year : // show year : node.label
case .Month : // show month : node.label
case .Book : // show book name : node.label and/or node.book
default : break
}
return view
}
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int
{
let node = (item as? BookNode) ?? topNode
return node.children.count
}
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any
{
let node = (item as? BookNode) ?? topNode
return node.children[index]
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool
{
let node = (item as? BookNode) ?? topNode
return node.children.count > 0
}
如果您的程序需要允许 adding/changing/removing 本书,BookNode class 可用于反映个人更改(例如,删除一个书子或添加一个新书)。然后,您只需要在大纲上调用 reloadData(),而不必从数据库中取回所有内容。
我在 macOS 上使用 swift 4,我有一个 NSOutlineView:
我从核心数据中获取数据。
结构:
- 实体人(与实体书的关系)
- 实体书
我对此结果的代码:
@IBOutlet weak var myOutlineView: NSOutlineView!
let context = (NSApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var people = [Person]()
override func viewWillAppear() {
requestPeople()
}
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
let view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: self) as? CustomCell
if let person = item as? Person {
// Show Person
} else if let book = item as? Book {
// Show Books
}
return view
}
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
if let person = item as? Person {
return person.books.count
}
return people.count
}
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
if let person = item as? Person {
return person.books[index]
}
return people[index]
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
if let person = item as? Person {
return person.books.count > 0
}
return false
}
func requestPeople() {
let request = NSFetchRequest<Person>(entityName: "Person")
do {
people = try context.fetch(request)
myOutlineView.reloadData()
} catch { print(error) }
}
现在我的问题是: 我想创建另一个大纲视图。
我的 Book 实体看起来像这样(属性):
- 名字
- 创建日期
我的新大纲视图应该采用这种结构:
+ Year
++ Month
+++ Bookname
但我不知道如何实现这个结构。 和我的第一个大纲视图不一样。
有人可以帮我吗?
=======
我想我已经为年份和月份创建了没有重复的数组。 为此,我尝试使用此函数来获取数据:
var year = [String]()
var month = [String]()
var books = [Book]()
func requestBooks() {
let request = NSFetchRequest<Book>(entityName: "Book")
do {
books = try context.fetch(request)
for x in 0 ...< books.count {
if !year.contains("\(Calendar.current.component(.year, from: books[x].creationDate))") {
year.append("\(Calendar.current.component(.year, from: books[x].creationDate))")
}
if !month.contains("\(Calendar.current.component(.month, from: books[x].creationDate))") {
month.append("\(Calendar.current.component(.month, from: books[x].creationDate))")
}
}
myOutlineView.reloadData()
} catch { print(error) }
}
当您的底层数据结构是分层的(即树结构)时,多级大纲更易于管理。
以下是如何为图书创建 "Tree" 节点 class 的示例:
class BookNode
{
// levels and relationships, from parent to children
enum Level { case Top, Year, Month, Book }
let subLevels:[Level:Level] = [ .Top:.Year, .Year:.Month, .Month:.Book ]
var label = "" // description and unique "key"
var level = Level.Top
var children : [BookNode] = []
var book : Book! = nil // .Book level will store the actual Book
// add book to hierarchy, auto-create intermediate levels
func add(_ book:Book)
{
var subLabel = ""
switch level
{
case .Top : subLabel = String(Calendar.current.component(.year, from:book.creationDate))
case .Year : subLabel = String(Calendar.current.component(.month, from:book.creationDate))
case .Month : subLabel = book.name
case .Book : self.book = book // last level stores the book
return // and has no children
}
// Add branch (.Year, .Month) or leaf (.Book) node as needed
var subNode:BookNode! = children.first{[=10=].label == subLabel}
if subNode == nil
{
subNode = BookNode()
subNode.level = subLevels[level]!
subNode.label = subLabel
children.append(subNode)
}
// keep adding recursively down to .Book level
subNode.add(book)
}
}
您的数据将存储在 BookNodes 的层次结构中,您可以从提取请求中加载它 (您可以像我一样对其进行预排序,或者将其留给 BookNode class)
var topNode = BookNode()
func requestBooks()
{
let request = NSFetchRequest<Book>(entityName: "Book")
do {
let books = try context.fetch(request)
topNode = BookNode()
for book in books.sorted(by:{[=11=].creationDate < .creationDate})
{
topNode.add(book)
}
}
}
有了这个,使用 BookNodes 作为大纲项目将很容易响应你的大纲协议:
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView?
{
let view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Cell"), owner: self) as? CustomCell
let node = (item as? BookNode) ?? topNode
switch node.level
{
case .Year : // show year : node.label
case .Month : // show month : node.label
case .Book : // show book name : node.label and/or node.book
default : break
}
return view
}
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int
{
let node = (item as? BookNode) ?? topNode
return node.children.count
}
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any
{
let node = (item as? BookNode) ?? topNode
return node.children[index]
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool
{
let node = (item as? BookNode) ?? topNode
return node.children.count > 0
}
如果您的程序需要允许 adding/changing/removing 本书,BookNode class 可用于反映个人更改(例如,删除一个书子或添加一个新书)。然后,您只需要在大纲上调用 reloadData(),而不必从数据库中取回所有内容。