我正在爲Mac OS X編寫一個文本編輯器。我需要在NSTextView中顯示隱藏的字符(如空格,製表符和特殊字符)。我花了很多時間尋找如何做到這一點,但到目前爲止我還沒有找到答案。如果有人能指出我的方向正確,我會很感激。在NSTextView中顯示隱藏的字符
回答
看看NSLayoutManager類。你的NSTextView將有一個與之關聯的佈局管理器,佈局管理器負責將一個字符(空格,製表符等)與一個字形(在屏幕上繪製的那個字符的圖像)相關聯。
就你而言,你可能最感興趣的是replaceGlyphAtIndex:withGlyph:
方法,它可以讓你替換單個字形。
我所做的是在NSLayoutManager子類中覆蓋下面的方法。
- (void)drawGlyphsForGlyphRange:(NSRange)range atPoint:(NSPoint)origin
{
[super drawGlyphsForGlyphRange:range atPoint:origin];
for (int i = range.location; i != range.location + range.length; i++)
{
// test each character in this range
// if appropriate replace it with -replaceGlyphAtIndex:withGlyph:
}
}
我循環遍歷每個字符的索引。我現在面臨的問題是如何確定在每個位置找到的字符。我應該使用NSLayoutManager方法還是詢問NSTextView本身?前者的指數與後者相同嗎?
我可以通過-glyphAtIndex得到一個單獨的字形:但我無法弄清楚如何確定它對應的字符。
你得到這個字符的代碼點: NSString * completeString = [[self textStorage] string]; NSUInteger characterIndex = [self characterIndexForGlyphAtIndex:index]; unichar characterToCheck = [completeString characterAtIndex:characterIndex]; – JanX2 2012-06-27 14:15:54
我解決了NSGlyphs和NSTextView中相應unichar之間轉換的問題。下面的代碼精美的作品,並與子彈可見的文字代替空格:
- (void)drawGlyphsForGlyphRange:(NSRange)range atPoint:(NSPoint)origin
{
NSFont *font = [[CURRENT_TEXT_VIEW typingAttributes]
objectForKey:NSFontAttributeName];
NSGlyph bullet = [font glyphWithName:@"bullet"];
for (int i = range.location; i != range.location + range.length; i++)
{
unsigned charIndex = [self characterIndexForGlyphAtIndex:i];
unichar c =[[[self textStorage] string] characterAtIndex:charIndex];
if (c == ' ')
[self replaceGlyphAtIndex:charIndex withGlyph:bullet];
}
[super drawGlyphsForGlyphRange:range atPoint:origin];
}
也許 - [NSLayoutManager setShowsControlCharacters:]和/或 - [NSLayoutManager setShowsInvisibleCharacters:]會做你想要什麼。
幾年前,我寫了一個文本編輯器 - 這是一些無意義的代碼,應該讓你看着(希望)正確的方向(這是一個NSLayoutManager子類順便說一句 - 是的,我知道它像普通的廚房水槽一樣泄漏) :
- (void)drawGlyphsForGlyphRange:(NSRange)glyphRange atPoint:(NSPoint)containerOrigin
{
if ([[[[MJDocumentController sharedDocumentController] currentDocument] editor] showInvisibles])
{
//init glyphs
unichar crlf = 0x00B6;
NSString *CRLF = [[NSString alloc] initWithCharacters:&crlf length:1];
unichar space = 0x00B7;
NSString *SPACE = [[NSString alloc] initWithCharacters:&space length:1];
unichar tab = 0x2192;
NSString *TAB = [[NSString alloc] initWithCharacters:&tab length:1];
NSString *docContents = [[self textStorage] string];
NSString *glyph;
NSPoint glyphPoint;
NSRect glyphRect;
NSDictionary *attr = [[NSDictionary alloc] initWithObjectsAndKeys:[NSUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"invisiblesColor"]], NSForegroundColorAttributeName, nil];
//loop thru current range, drawing glyphs
int i;
for (i = glyphRange.location; i < NSMaxRange(glyphRange); i++)
{
glyph = @"";
//look for special chars
switch ([docContents characterAtIndex:i])
{
//space
case ' ':
glyph = SPACE;
break;
//tab
case '\t':
glyph = TAB;
break;
//eol
case 0x2028:
case 0x2029:
case '\n':
case '\r':
glyph = CRLF;
break;
//do nothing
default:
glyph = @"";
break;
}
//should we draw?
if ([glyph length])
{
glyphPoint = [self locationForGlyphAtIndex:i];
glyphRect = [self lineFragmentRectForGlyphAtIndex:i effectiveRange:NULL];
glyphPoint.x += glyphRect.origin.x;
glyphPoint.y = glyphRect.origin.y;
[glyph drawAtPoint:glyphPoint withAttributes:attr];
}
}
}
[super drawGlyphsForGlyphRange:glyphRange atPoint:containerOrigin];
}
這裏是一個完全可行且乾淨實施
@interface GILayoutManager : NSLayoutManager
@end
@implementation GILayoutManager
- (void)drawGlyphsForGlyphRange:(NSRange)range atPoint:(NSPoint)point {
NSTextStorage* storage = self.textStorage;
NSString* string = storage.string;
for (NSUInteger glyphIndex = range.location; glyphIndex < range.location + range.length; glyphIndex++) {
NSUInteger characterIndex = [self characterIndexForGlyphAtIndex: glyphIndex];
switch ([string characterAtIndex:characterIndex]) {
case ' ': {
NSFont* font = [storage attribute:NSFontAttributeName atIndex:characterIndex effectiveRange:NULL];
[self replaceGlyphAtIndex:glyphIndex withGlyph:[font glyphWithName:@"periodcentered"]];
break;
}
case '\n': {
NSFont* font = [storage attribute:NSFontAttributeName atIndex:characterIndex effectiveRange:NULL];
[self replaceGlyphAtIndex:glyphIndex withGlyph:[font glyphWithName:@"carriagereturn"]];
break;
}
}
}
[super drawGlyphsForGlyphRange:range atPoint:point];
}
@end
安裝,使用:
[myTextView.textContainer replaceLayoutManager:[[GILayoutManager alloc] init]];
查找字體字形的名字,你必須去CoreGraphics中:
CGFontRef font = CGFontCreateWithFontName(CFSTR("Menlo-Regular"));
for (size_t i = 0; i < CGFontGetNumberOfGlyphs(font); ++i) {
printf("%s\n", [CFBridgingRelease(CGFontCopyGlyphNameForGlyph(font, i)) UTF8String]);
}
非常感謝你分享這個。 – uchuugaka 2015-11-26 09:36:50
這裏是波爾在斯威夫特的解決方案:
class MyLayoutManager: NSLayoutManager {
override func drawGlyphsForGlyphRange(glyphsToShow: NSRange, atPoint origin: NSPoint) {
if let storage = self.textStorage {
let s = storage.string
let startIndex = s.startIndex
for var glyphIndex = glyphsToShow.location; glyphIndex < glyphsToShow.location + glyphsToShow.length; glyphIndex++ {
let characterIndex = self.characterIndexForGlyphAtIndex(glyphIndex)
let ch = s[startIndex.advancedBy(characterIndex)]
switch ch {
case " ":
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
let g = font.glyphWithName("periodcentered")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
}
case "\n":
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
// let g = font.glyphWithName("carriagereturn")
let g = font.glyphWithName("paragraph")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
}
case "\t":
let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
if let font = attrs[NSFontAttributeName] {
let g = font.glyphWithName("arrowdblright")
self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
}
default:
break
}
}
}
super.drawGlyphsForGlyphRange(glyphsToShow, atPoint: origin)
}
}
並列出字形名稱:
func listFonts() {
let font = CGFontCreateWithFontName("Menlo-Regular")
for var i:UInt16 = 0; i < UInt16(CGFontGetNumberOfGlyphs(font)); i++ {
if let name = CGFontCopyGlyphNameForGlyph(font, i) {
print("name: \(name) at index \(i)")
}
}
}
- 1. 在Adobe Edge中顯示隱藏符號
- 2. 顯示和隱藏密碼字符
- 3. AngularJS隱藏和顯示一個字符
- 4. 從url中隱藏/顯示div的字符串在PHP中
- 5. 在顯示/隱藏div中顯示/隱藏div
- 6. 是否可以在CodeMirror中顯示隱藏的字符?
- 7. 隱藏/顯示在PHP中
- 8. 在javascript中顯示/隱藏
- 9. jquery顯示/隱藏字段
- 10. 顯示隱藏字段simple_form
- 11. 如何在H2中查詢的結果中顯示字段的隱藏字符?
- 12. 如何在Oracle中的查詢結果中顯示字段的隱藏字符?
- 13. IE中顯示隱藏字段值
- 14. 顯示隱藏字段在運行時
- 15. 隱藏和顯示文字不隱藏在jquery
- 16. 的Javascript:顯示/隱藏的名字
- 17. 在顯示/隱藏時顯示屬性
- 18. 在javascript中顯示隱藏的div?
- 19. 顯示\隱藏在Surfaceview中的AdMob
- 20. 在鉻中顯示隱藏的值
- 21. 在speedbar中顯示隱藏的文件
- 22. 顯示/隱藏腳本顯示僅去年隱藏的div
- 23. 顯示/隱藏時刪除的文本顯示/隱藏
- 24. 當我顯示div時,隱藏的div-img隱藏不顯示
- 25. 顯示隱藏jQuery顯示所有隱藏的tr
- 26. jQuery的顯示/隱藏顯示或隱藏
- 27. 隱藏字符
- 28. 隱藏字符
- 29. 隱藏/顯示Android中
- 30. 隱藏和顯示在angularjs
@由於文檔稀疏,Pol在硬類中發佈了更完整的信息。但是兩者都有一個侷限性,因爲這個方法不推薦使用,而且新方法看起來有些困難,因爲它使用C數組:D我將在此基礎上添加一些示例。 – uchuugaka 2015-11-26 09:39:28