gpt4 book ai didi

swift - 在输入 NSTextField 时过滤 NSTable - 自动选择第一行

转载 作者:IT王子 更新时间:2023-10-29 05:51:46 24 4
gpt4 key购买 nike

我有一个 NSTextView 字段,它在用户输入时过滤一个 NSTable 表。我已经成功实现了表过滤。

现在,我的目标是自动选择第一个结果(表中的第一行)并允许用户在键入搜索查询时使用箭头键在结果之间移动。在表中的结果之间移动时,输入字段应保持焦点。 (这类似于 Spotlight 的工作方式)。

这是应用程序现在的样子:

app

这是我的ViewController:

import Cocoa

class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate, NSTextFieldDelegate {

@IBOutlet weak var field: NSTextField!
@IBOutlet weak var table: NSTableView!

var projects: [Project] = []

override func viewDidLoad() {
super.viewDidLoad()

projects = Project.all()

field.delegate = self
table.dataSource = self
table.delegate = self
}

override func controlTextDidChange(_ obj: Notification) {
let query = (obj.object as! NSTextField).stringValue

projects = Project.all().filter { $0.title.contains(query) }

table.reloadData()
}

func numberOfRows(in tableView: NSTableView) -> Int {
return projects.count
}

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "FirstCell"), owner: nil) as? NSTableCellView {
cell.textField?.stringValue = projects[row].title
return cell
}

return nil
}
}

这是Project

struct Project {
var title: String = ""

static func all() -> [Project] {
return [
Project(title: "first project"),
Project(title: "second project"),
Project(title: "third project"),
Project(title: "fourth project"),
];
}
}

谢谢

最佳答案

这个有点,在@Willeke 发布的副本中已经有一个答案,但是 1) 这个答案是在 Objective-C 中,而不是 Swift,2) 我可以提供更详细的答案(有图片!),和3) 我正在厚颜无耻地追求赏金(收购规则 #110)。因此,考虑到这一点,以下是我将如何实现您想要做的事情:

不要使用 NSTextView;使用 NSTextField,或者更好的是 NSSearchFieldNSSearchField 很棒,因为我们可以在 Interface Builder 中设置它来创建过滤器谓词,几乎不需要代码。为此,我们要做的就是在我们的 View Controller 中创建一个 NSPredicate 属性,然后设置搜索字段的 Bindings Inspector 以指向它:

enter image description here

然后您可以创建一个 Array Controller,将其 Filter Predicate 绑定(bind)到同一属性,并将其 Content Array 绑定(bind)绑定(bind)到 View Controller 上的属性:

enter image description here

当然,还要将 TableView 绑定(bind)到数组 Controller :

enter image description here

最后但同样重要的是,将表格单元格 View 中的文本字段绑定(bind)到 title 属性:

enter image description here

在 Interface Builder 中完成所有设置后,我们几乎不需要任何代码。我们只需要定义 Project 类(所有属性都需要标记为 @objc 以便 Cocoa Bindings 系统可以看到它们):

class Project: NSObject {
@objc let title: String

init(title: String) {
self.title = title
super.init()
}
}

我们还需要在我们的 View Controller 上为项目、数组 Controller 和过滤器谓词设置属性。过滤器谓词需要是动态的,以便 Cocoa Bindings 在更改和更新 UI 时可以得到通知。如果 projects 可以改变,也让 dynamic 发生变化,这样对它的任何改变都会反射(reflect)在 UI 中(否则,你可以去掉 dynamic 然后让它成为 @objc let)。

class ViewController: NSViewController {
@IBOutlet var arrayController: NSArrayController!

@objc dynamic var projects = [
Project(title: "Foo"),
Project(title: "Bar"),
Project(title: "Baz"),
Project(title: "Qux")
]

@objc dynamic var filterPredicate: NSPredicate? = nil
}

最后但并非最不重要的一点是,我们的 View Controller 上的扩展使其符合 NSSearchFieldDelegate(或 NSTextFieldDelegate,如果您使用的是 NSTextField 而不是 NSSearchField),我们将在其上实现 control(:textView:doCommandBy:) 方法。基本上我们拦截由搜索字段的字段编辑器执行的文本编辑命令,如果我们得到 moveUp:moveDown:,返回 true 到告诉现场编辑器我们将改为处理这些命令。对于这两个选择器以外的所有内容,返回 false 以告诉字段编辑器执行它通常执行的操作。

请注意,这就是您应该使用 NSTextFieldNSSearchField 而不是 NSTextView 的原因;此委托(delegate)方法只会为 NSControl 子类调用,而 NSTextView 则不会。

extension ViewController: NSSearchFieldDelegate {
func control(_: NSControl, textView _: NSTextView, doCommandBy selector: Selector) -> Bool {
switch selector {
case #selector(NSResponder.moveUp(_:)):
self.arrayController.selectPrevious(self)
return true
case #selector(NSResponder.moveDown(_:)):
self.arrayController.selectNext(self)
return true
default:
return false
}
}
}

瞧!

(当然,如果你更喜欢手动填充表格 View 而不是使用绑定(bind),你可以忽略大部分内容并只实现 control(:textView:doCommandBy:),更新表格的选择手动而不是要求你的数组 Controller 来做。当然,使用绑定(bind)会产生漂亮、干净的代码,这就是我喜欢它的原因。)

关于swift - 在输入 NSTextField 时过滤 NSTable - 自动选择第一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48481006/

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