gpt4 book ai didi

swift - 构建带有复选标记的 NSOutline View

转载 作者:可可西里 更新时间:2023-11-01 01:57:08 25 4
gpt4 key购买 nike

我希望使用正确的 Apple 推荐方法将复选框添加到 NSOutlineview - 但文档中并不清楚。

我如何添加允许用户的行为,如果我点击一个父复选框,它会选择子项,如果我取消单击它 - 它会取消选择该项目的子项?

编辑:我简化了我的问题并添加了图像以使其更清晰(希望如此)

我的方法:我一直在使用 Code Different 的精彩答案在我的 mac 应用程序中构建大纲 View 。 https://stackoverflow.com/a/45384599/559760- 我选择使用手动过程而不是使用 CocoaBindings 来填充 NSoutLine View 。

我在堆栈 View 中添加了一个复选框,这似乎是正确的方法:

Example with the checkbox

我的解决方案涉及创建一个数组来保存 View Controller 中的选定项目,然后创建用于添加和删除的函数

var selectedItems: [Int]?

@objc func cellWasClicked(sender: NSButton) {
let newCheckBoxState = sender.state
let tag = sender.tag
switch newCheckBoxState {
case NSControl.StateValue.on:
print("adding- \(sender.tag)")
case NSControl.StateValue.off:
print("removing- \(sender.tag)")
default:
print("unhandled button state \(newCheckBoxState)")
}

我通过分配给复选框的标签来识别复选框

最佳答案

为了 future Google 员工的利益,我将重复我在 other answer 中写的东西.这里的不同之处在于,它有一个额外的要求,即列是可编辑的,我已经改进了这项技术。


NSOutlineView 的关键是您必须为每一行指定一个标识符,可以是字符串、数字或唯一标识该行的对象。 NSOutlineView 称其为 item。基于此 item,您将查询您的数据模型以填充大纲。

在这个答案中,我们将设置一个包含 2 列的大纲 View :一个可编辑的 Is Selected 列和一个不可编辑的 Title 列。


界面生成器设置

  • 选择第一列并将其标识符设置为isSelected
  • 选择第二列并将其标识符设置为title

set column identifier

  • 选择第一列中的单元格并将其标识符更改为 isSelectedCell
  • 选择第二列中的单元格并将其标识符更改为 titleCell

set cell identifier

一致性在这里很重要。单元格的标识符应等于其列的标识符 + Cell


带有复选框的单元格

默认的 NSTableCellView 包含一个不可编辑的文本字段。我们需要一个复选框,所以我们必须设计自己的单元格。

CheckboxCellView.swift

import Cocoa

/// A set of methods that `CheckboxCelView` use to communicate changes to another object
protocol CheckboxCellViewDelegate {
func checkboxCellView(_ cell: CheckboxCellView, didChangeState state: NSControl.StateValue)
}

class CheckboxCellView: NSTableCellView {

/// The checkbox button
@IBOutlet weak var checkboxButton: NSButton!

/// The item that represent the row in the outline view
/// We may potentially use this cell for multiple outline views so let's make it generic
var item: Any?

/// The delegate of the cell
var delegate: CheckboxCellViewDelegate?

override func awakeFromNib() {
checkboxButton.target = self
checkboxButton.action = #selector(self.didChangeState(_:))
}

/// Notify the delegate that the checkbox's state has changed
@objc private func didChangeState(_ sender: NSObject) {
delegate?.checkboxCellView(self, didChangeState: checkboxButton.state)
}
}

连接 socket

  • 删除 isSelected 列中的默认文本字段
  • 从对象库中拖入一个复选框
  • 选择 NSTableCellView 并将其类更改为 CheckboxCellView
  • 打开助理编辑器并连接 socket

set custom class and connect the outlet


View Controller

最后是 View Controller 的代码:

import Cocoa


/// A class that represents a row in the outline view. Add as many properties as needed
/// for the columns in your outline view.
class OutlineViewRow {
var title: String
var isSelected: Bool
var children: [OutlineViewRow]

init(title: String, isSelected: Bool, children: [OutlineViewRow] = []) {
self.title = title
self.isSelected = isSelected
self.children = children
}

func setIsSelected(_ isSelected: Bool, recursive: Bool) {
self.isSelected = isSelected
if recursive {
self.children.forEach { $0.setIsSelected(isSelected, recursive: true) }
}
}
}

/// A enum that represents the list of columns in the outline view. Enum is preferred over
/// string literals as they are checked at compile-time. Repeating the same strings over
/// and over again are error-prone. However, you need to make the Column Identifier in
/// Interface Builder with the raw value used here.
enum OutlineViewColumn: String {
case isSelected = "isSelected"
case title = "title"

init?(_ tableColumn: NSTableColumn) {
self.init(rawValue: tableColumn.identifier.rawValue)
}

var cellIdentifier: NSUserInterfaceItemIdentifier {
return NSUserInterfaceItemIdentifier(self.rawValue + "Cell")
}
}


class ViewController: NSViewController {
@IBOutlet weak var outlineView: NSOutlineView!

/// The rows of the outline view
let rows: [OutlineViewRow] = {
var child1 = OutlineViewRow(title: "p1-child1", isSelected: true)
var child2 = OutlineViewRow(title: "p1-child2", isSelected: true)
var child3 = OutlineViewRow(title: "p1-child3", isSelected: true)
let parent1 = OutlineViewRow(title: "parent1", isSelected: true, children: [child1, child2, child3])

child1 = OutlineViewRow(title: "p2-child1", isSelected: true)
child2 = OutlineViewRow(title: "p2-child2", isSelected: true)
child3 = OutlineViewRow(title: "p2-child3", isSelected: true)
let parent2 = OutlineViewRow(title: "parent2", isSelected: true, children: [child1, child2, child3])

child1 = OutlineViewRow(title: "p3-child1", isSelected: true)
child2 = OutlineViewRow(title: "p3-child2", isSelected: true)
child3 = OutlineViewRow(title: "p3-child3", isSelected: true)
let parent3 = OutlineViewRow(title: "parent3", isSelected: true, children: [child1, child2, child3])

child3 = OutlineViewRow(title: "p4-child3", isSelected: true)
child2 = OutlineViewRow(title: "p4-child2", isSelected: true, children: [child3])
child1 = OutlineViewRow(title: "p4-child1", isSelected: true, children: [child2])
let parent4 = OutlineViewRow(title: "parent4", isSelected: true, children: [child1])

return [parent1, parent2, parent3, parent4]
}()

override func viewDidLoad() {
super.viewDidLoad()
outlineView.dataSource = self
outlineView.delegate = self
}
}

extension ViewController: NSOutlineViewDataSource, NSOutlineViewDelegate {
/// Returns how many children a row has. `item == nil` means the root row (not visible)
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
switch item {
case nil: return rows.count
case let row as OutlineViewRow: return row.children.count
default: return 0
}
}

/// Returns the object that represents the row. `NSOutlineView` calls this the `item`
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
switch item {
case nil: return rows[index]
case let row as OutlineViewRow: return row.children[index]
default: return NSNull()
}
}

/// Returns whether the row can be expanded
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
switch item {
case nil: return !rows.isEmpty
case let row as OutlineViewRow: return !row.children.isEmpty
default: return false
}
}

/// Returns the view that display the content for each cell of the outline view
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
guard let item = item as? OutlineViewRow, let column = OutlineViewColumn(tableColumn!) else { return nil }

switch column {
case .isSelected:
let cell = outlineView.makeView(withIdentifier: column.cellIdentifier, owner: self) as! CheckboxCellView
cell.checkboxButton.state = item.isSelected ? .on : .off
cell.delegate = self
cell.item = item
return cell

case .title:
let cell = outlineView.makeView(withIdentifier: column.cellIdentifier, owner: self) as! NSTableCellView
cell.textField?.stringValue = item.title
return cell
}
}
}

extension ViewController: CheckboxCellViewDelegate {
/// A delegate function where we can act on update from the checkbox in the "Is Selected" column
func checkboxCellView(_ cell: CheckboxCellView, didChangeState state: NSControl.StateValue) {
guard let item = cell.item as? OutlineViewRow else { return }

// The row and its children are selected if state == .on
item.setIsSelected(state == .on, recursive: true)

// This is more efficient than calling reload on every child since collapsed children are
// not reloaded. They will be reloaded when they become visible
outlineView.reloadItem(item, reloadChildren: true)
}
}

结果

result

关于swift - 构建带有复选标记的 NSOutline View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51484452/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com