如何在不减慢过程的情况下使用颜色为文本着色?
How to use colour for text colouring without slowing down the process?
我发现字符串着色的时间取决于使用了多少不同的 NSColors。在下面的代码中,如果我对三种情况只使用一种颜色,那么文本着色过程比对这三种情况使用三种不同颜色的情况快 3 倍,每种情况每种颜色。为什么 ?有没有办法不减慢三种不同颜色的着色速度?
for i in 0..<arrayOfNSRangesForA.count
{
textFromStorage.addAttribute(NSForegroundColorAttributeName, value: NSColor.green, range: arrayOfNSRangesForA[i])
}
for i in 0..<arrayOfNSRangesForT.count
{
textFromStorage.addAttribute(NSForegroundColorAttributeName, value: NSColor.green, range: arrayOfNSRangesForT[i])
}
for i in 0..<arrayOfNSRangesForC.count
{
textFromStorage.addAttribute(NSForegroundColorAttributeName, value: NSColor.green, range: arrayOfNSRangesForC[i])
}
更新
我又发现了一件坏事。当我将颜色从 NSForegroundColorAttributeName
更改为 NSBackgroundColorAttributeName
时,运行 时间显着增加 - 10 倍。对于 20 000 个字符,它是一种颜色,NSForegroundColorAttributeName
- 1 秒,NSBackgroundColorAttributeName
- 10 秒;如果三种颜色 - 相应地为 3 秒和 30 秒。对我来说,这是 Swift 非常糟糕的功能!!! DNA(ATGC 序列)着色无法正常工作,因为 DNA 的长度有数千个 A、T、G、C 字符!
更新
在评论中,我建议只为文本的可见部分着色。我已经尝试过这种方法,与我以标准方式所做的相比,即使是较短的文本也更糟糕。因此,我为文本的可见部分设置了 NSRange 文本,并在滚动时通过使用通知在滚动时动态着色。这是一个糟糕的方法。
您是否尝试过使用 ciColor
而不是属性? ciColors
可与文本、图像和背景一起使用。
你可以这样试试:
txtField.textColor?.ciColor.red
最大的障碍是在文本视图中布置所有这些属性字符。着色 DNA 序列需要最少的时间。无需编写自己的布局管理器或文本存储 class,您可以采用 divide-and-conquer 方法,一次对文本视图进行着色:
@IBOutlet var textView: NSTextView!
var dnaSequence: String!
var attributedDNASequence: NSAttributedString!
@IBAction func colorize(_ sender: Any) {
self.dnaSequence = "ACGT" // your plaintext DNA sequence
self.attributedDNASequence = self.makeAttributedDNASequence()
// Rendering long string with the same attributes throughout is extremely fast
self.textView.textStorage?.setAttributedString(NSAttributedString(string: dnaSequence))
let step = 10_000 // colorize 10k characters at a time
let delay = 0.2 // delay between each render
for (i, location) in stride(from: 0, to: self.dnaSequence.characters.count, by: step).enumerated() {
let length = min(step, self.dnaSequence.characters.count - location)
let range = NSMakeRange(location, length)
// Since we are modifying the textStorage of a GUI object (NSTextView)
// we should do it on the main thread
DispatchQueue.main.asyncAfter(deadline: .now() + (delay * Double(i))) {
let subtext = self.attributedDNASequence.attributedSubstring(from: range)
print("Replacing text in range \(location) to \(location + length)")
self.textView.textStorage?.replaceCharacters(in: range, with: subtext)
}
}
}
// MARK: -
var colorA = NSColor.red
var colorC = NSColor.green
var colorG = NSColor.blue
var colorT = NSColor.black
func makeAttributedDNASequence() -> NSAttributedString {
let attributedText = NSMutableAttributedString(string: dnaSequence)
var index = dnaSequence.startIndex
var color: NSColor!
for i in 0..<dnaSequence.characters.count {
switch dnaSequence[index] {
case "A":
color = colorA
case "C":
color = colorC
case "G":
color = colorG
case "T":
color = colorT
default:
color = NSColor.black
}
attributedText.addAttribute(NSForegroundColorAttributeName, value: color, range: NSMakeRange(i,1))
index = dnaSequence.index(after: index)
}
return attributedText
}
诀窍是让应用程序尽可能地响应,这样用户就不会意识到事情仍在后台进行。使用小 delay
(<= 0.3 秒)我无法足够快地滚动鼠标以在所有内容都被着色(100k 个字符)之前到达文本视图的末尾。
在 10 万个字符的测试中,彩色字符串第一次出现在文本视图中需要 0.7 秒,而不是一次完成所有操作时的 7 秒。
我发现字符串着色的时间取决于使用了多少不同的 NSColors。在下面的代码中,如果我对三种情况只使用一种颜色,那么文本着色过程比对这三种情况使用三种不同颜色的情况快 3 倍,每种情况每种颜色。为什么 ?有没有办法不减慢三种不同颜色的着色速度?
for i in 0..<arrayOfNSRangesForA.count
{
textFromStorage.addAttribute(NSForegroundColorAttributeName, value: NSColor.green, range: arrayOfNSRangesForA[i])
}
for i in 0..<arrayOfNSRangesForT.count
{
textFromStorage.addAttribute(NSForegroundColorAttributeName, value: NSColor.green, range: arrayOfNSRangesForT[i])
}
for i in 0..<arrayOfNSRangesForC.count
{
textFromStorage.addAttribute(NSForegroundColorAttributeName, value: NSColor.green, range: arrayOfNSRangesForC[i])
}
更新
我又发现了一件坏事。当我将颜色从 NSForegroundColorAttributeName
更改为 NSBackgroundColorAttributeName
时,运行 时间显着增加 - 10 倍。对于 20 000 个字符,它是一种颜色,NSForegroundColorAttributeName
- 1 秒,NSBackgroundColorAttributeName
- 10 秒;如果三种颜色 - 相应地为 3 秒和 30 秒。对我来说,这是 Swift 非常糟糕的功能!!! DNA(ATGC 序列)着色无法正常工作,因为 DNA 的长度有数千个 A、T、G、C 字符!
更新 在评论中,我建议只为文本的可见部分着色。我已经尝试过这种方法,与我以标准方式所做的相比,即使是较短的文本也更糟糕。因此,我为文本的可见部分设置了 NSRange 文本,并在滚动时通过使用通知在滚动时动态着色。这是一个糟糕的方法。
您是否尝试过使用 ciColor
而不是属性? ciColors
可与文本、图像和背景一起使用。
你可以这样试试:
txtField.textColor?.ciColor.red
最大的障碍是在文本视图中布置所有这些属性字符。着色 DNA 序列需要最少的时间。无需编写自己的布局管理器或文本存储 class,您可以采用 divide-and-conquer 方法,一次对文本视图进行着色:
@IBOutlet var textView: NSTextView!
var dnaSequence: String!
var attributedDNASequence: NSAttributedString!
@IBAction func colorize(_ sender: Any) {
self.dnaSequence = "ACGT" // your plaintext DNA sequence
self.attributedDNASequence = self.makeAttributedDNASequence()
// Rendering long string with the same attributes throughout is extremely fast
self.textView.textStorage?.setAttributedString(NSAttributedString(string: dnaSequence))
let step = 10_000 // colorize 10k characters at a time
let delay = 0.2 // delay between each render
for (i, location) in stride(from: 0, to: self.dnaSequence.characters.count, by: step).enumerated() {
let length = min(step, self.dnaSequence.characters.count - location)
let range = NSMakeRange(location, length)
// Since we are modifying the textStorage of a GUI object (NSTextView)
// we should do it on the main thread
DispatchQueue.main.asyncAfter(deadline: .now() + (delay * Double(i))) {
let subtext = self.attributedDNASequence.attributedSubstring(from: range)
print("Replacing text in range \(location) to \(location + length)")
self.textView.textStorage?.replaceCharacters(in: range, with: subtext)
}
}
}
// MARK: -
var colorA = NSColor.red
var colorC = NSColor.green
var colorG = NSColor.blue
var colorT = NSColor.black
func makeAttributedDNASequence() -> NSAttributedString {
let attributedText = NSMutableAttributedString(string: dnaSequence)
var index = dnaSequence.startIndex
var color: NSColor!
for i in 0..<dnaSequence.characters.count {
switch dnaSequence[index] {
case "A":
color = colorA
case "C":
color = colorC
case "G":
color = colorG
case "T":
color = colorT
default:
color = NSColor.black
}
attributedText.addAttribute(NSForegroundColorAttributeName, value: color, range: NSMakeRange(i,1))
index = dnaSequence.index(after: index)
}
return attributedText
}
诀窍是让应用程序尽可能地响应,这样用户就不会意识到事情仍在后台进行。使用小 delay
(<= 0.3 秒)我无法足够快地滚动鼠标以在所有内容都被着色(100k 个字符)之前到达文本视图的末尾。
在 10 万个字符的测试中,彩色字符串第一次出现在文本视图中需要 0.7 秒,而不是一次完成所有操作时的 7 秒。