2008-11-18 51 views
5

我正在爲Mac OS X編寫一個文本編輯器。我需要在NSTextView中顯示隱藏的字符(如空格,製表符和特殊字符)。我花了很多時間尋找如何做到這一點,但到目前爲止我還沒有找到答案。如果有人能指出我的方向正確,我會很感激。在NSTextView中顯示隱藏的字符

回答

4

看看NSLayoutManager類。你的NSTextView將有一個與之關聯的佈局管理器,佈局管理器負責將一個字符(空格,製表符等)與一個字形(在屏幕上繪製的那個字符的圖像)相關聯。

就你而言,你可能最感興趣的是replaceGlyphAtIndex:withGlyph:方法,它可以讓你替換單個字形。

+0

@由於文檔稀疏,Pol在硬類中發佈了更完整的信息。但是兩者都有一個侷限性,因爲這個方法不推薦使用,而且新方法看起來有些困難,因爲它使用C數組:D我將在此基礎上添加一些示例。 – uchuugaka 2015-11-26 09:39:28

0

我所做的是在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得到一個單獨的字形:但我無法弄清楚如何確定它對應的字符。

+0

你得到這個字符的代碼點: NSString * completeString = [[self textStorage] string]; NSUInteger characterIndex = [self characterIndexForGlyphAtIndex:index]; unichar characterToCheck = [completeString characterAtIndex:characterIndex]; – JanX2 2012-06-27 14:15:54

2

我解決了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]; 
}
2

也許 - [NSLayoutManager setShowsControlCharacters:]和/或 - [NSLayoutManager setShowsInvisibleCharacters:]會做你想要什麼。

3

幾年前,我寫了一個文本編輯器 - 這是一些無意義的代碼,應該讓你看着(希望)正確的方向(這是一個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]; 
} 
4

這裏是一個完全可行且乾淨實施

@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]); 
} 
+0

非常感謝你分享這個。 – uchuugaka 2015-11-26 09:36:50

0

這裏是波爾在斯威夫特的解決方案:

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)") 
      } 
     } 
    }