2008-11-18 46 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)") 
      } 
     } 
    }