objective-c – 如何以编程方式将项目符号列表添加到NSTextView

前端之家收集整理的这篇文章主要介绍了objective-c – 如何以编程方式将项目符号列表添加到NSTextView前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这个问题可能听起来很奇怪,但我已经挣扎了好几天了.

我有一个NSTextView,可以显示一些带有一些格式选项的文本.其中之一是能够为选择或当前行打开/关闭子弹列表(最简单的一个).

我知道在NSTextView上有一个orderFrontListPanel:方法打开窗口,其中包含可供选择和编辑的可用列表参数(例如,当您按Menu-> Format-> List …时在TextView中).
我已经想出并实现了手动添加项目符号,NSTextView似乎几乎正确地使用它们.通过说几乎我的意思是它保留标签位置,继续“输入”列表,等等.但是有一些小故障不适合我,不同于标准实施.

我试图找到以编程方式设置列表的默认方式,就像通过“列表…”菜单完成一样没有运气.

我请求帮助,每一点点的信息都会受到赞赏:).

P.S.:我已经查看了TextView源代码,发现了很多有趣但没有迹象或线索如何以编程方式启用列表.

更新

还在调查.我发现当你发送orderFrontListPanel:到你的NSTextView然后选择项目符号并按回车键时,没有特殊的消息被发送到NSTextView.这意味着可以在弹出式面板中的某处构建项目符号列表,并直接设置为TextView的文本容器…

解决方法

以编程方式将项目符号列表添加到NSTextView的两种方法

方法1:

以下链接引导我使用第一种方法,但除非您想为子弹使用一些特殊的非Unicode字形,否则它将不必要地转向:

> Display hidden characters in NSTextView
> How to draw one NSGlyph,that hasn’t unicode representation?
> appendBezierPathWithGlyph fails in [NSBezierPath currentPoint]

这需要:(1)子类化布局管理器,用子弹字形替换某些任意字符; (2)带有firstLineHeadIndent的段落样式,比该缩进略大的制表位,以及用于组合两者的包裹线的headIndent.

布局管理器如下所示:

  1. #import <Foundation/Foundation.h>
  2.  
  3. @interface TickerLayoutManager : NSLayoutManager {
  4.  
  5. // Might as well let this class hold all the fonts used by the progress ticker.
  6. // That way they're all defined in one place,the init method.
  7. NSFont *fontNormal;
  8. NSFont *fontIndent; // smaller,for indented lines
  9. NSFont *fontBold;
  10.  
  11. NSGlyph glyphBullet;
  12. CGFloat fWidthGlyPHPlusSpace;
  13.  
  14. }
  15.  
  16. @property (nonatomic,retain) NSFont *fontNormal;
  17. @property (nonatomic,retain) NSFont *fontIndent;
  18. @property (nonatomic,retain) NSFont *fontBold;
  19. @property NSGlyph glyphBullet;
  20. @property CGFloat fWidthGlyPHPlusSpace;
  21.  
  22. @end
  23.  
  24. #import "TickerLayoutManager.h"
  25.  
  26. @implementation TickerLayoutManager
  27.  
  28. @synthesize fontNormal;
  29. @synthesize fontIndent;
  30. @synthesize fontBold;
  31. @synthesize glyphBullet;
  32. @synthesize fWidthGlyPHPlusSpace;
  33.  
  34. - (id)init {
  35. self = [super init];
  36. if (self) {
  37. self.fontNormal = [NSFont fontWithName:@"Baskerville" size:14.0f];
  38. self.fontIndent = [NSFont fontWithName:@"Baskerville" size:12.0f];
  39. self.fontBold = [NSFont fontWithName:@"Baskerville Bold" size:14.0f];
  40. // Get the bullet glyph.
  41. self.glyphBullet = [self.fontIndent glyphWithName:@"bullet"];
  42. // To determine its point size,put it in a Bezier path and take its bounds.
  43. NSBezierPath *bezierPath = [NSBezierPath bezierPath];
  44. [bezierPath moveToPoint:NSMakePoint(0.0f,0.0f)]; // prevents "No current point for line" exception
  45. [bezierPath appendBezierPathWithGlyph:self.glyphBullet inFont:self.fontIndent];
  46. NSRect rectGlyphOutline = [bezierPath bounds];
  47. // The bullet should be followed with a space,so get the combined size...
  48. NSSize sizeSpace = [@" " sizeWithAttributes:[NSDictionary dictionaryWithObject:self.fontIndent forKey:NSFontAttributeName]];
  49. self.fWidthGlyPHPlusSpace = rectGlyphOutline.size.width + sizeSpace.width;
  50. // ...which is for some reason inexact. If this number is too low,your bulleted text will be thrown to the line below,so add some boost.
  51. self.fWidthGlyPHPlusSpace *= 1.5; //
  52. }
  53.  
  54. return self;
  55. }
  56.  
  57. - (void)drawGlyphsForGlyphRange:(NSRange)range
  58. atPoint:(NSPoint)origin {
  59.  
  60. // The following prints only once,even though the textview's string is set 4 times,so this implementation is not too expensive.
  61. printf("\nCalling TickerLayoutManager's drawGlyphs method.");
  62.  
  63. NSString *string = [[self textStorage] string];
  64. for (int i = range.location; i < range.length; i++) {
  65. // Replace all occurrences of the ">" char with the bullet glyph.
  66. if ([string characterAtIndex:i] == '>')
  67. [self replaceGlyphAtIndex:i withGlyph:self.glyphBullet];
  68. }
  69.  
  70. [super drawGlyphsForGlyphRange:range atPoint:origin];
  71. }
  72.  
  73. @end

将布局管理器分配给窗口/视图控制器的awakeFromNib中的textview,如下所示:

  1. - (void) awakeFromNib {
  2.  
  3. // regular setup...
  4.  
  5. // Give the ticker display NSTextView its subclassed layout manager.
  6. TickerLayoutManager *newLayoutMgr = [[TickerLayoutManager alloc] init];
  7. NSTextContainer *textContainer = [self.txvProgressTicker textContainer];
  8. // Use "replaceLM" rather than "setLM," in order to keep shared relnshps intact.
  9. [textContainer replaceLayoutManager:newLayoutMgr];
  10. [newLayoutMgr release];
  11. // (Note: It is possible that all text-displaying controls in this class’s window will share this text container,as they would a field editor (a textview),although the fact that the ticker display is itself a textview might isolate it. Apple's "Text System Overview" is not clear on this point.)
  12.  
  13. }

然后添加一个类似这样的方法

  1. - (void) addProgressTickerLine:(NSString *)string
  2. inStyle:(uint8_t)uiStyle {
  3.  
  4. // Null check.
  5. if (!string)
  6. return;
  7.  
  8. // Prepare the font.
  9. // (As noted above,TickerLayoutManager holds all 3 ticker display fonts.)
  10. NSFont *font = nil;
  11. TickerLayoutManager *tickerLayoutMgr = (TickerLayoutManager *)[self.txvProgressTicker layoutManager];
  12. switch (uiStyle) {
  13. case kTickerStyleNormal:
  14. font = tickerLayoutMgr.fontNormal;
  15. break;
  16. case kTickerStyleIndent:
  17. font = tickerLayoutMgr.fontIndent;
  18. break;
  19. case kTickerStyleBold:
  20. font = tickerLayoutMgr.fontBold;
  21. break;
  22. default:
  23. font = tickerLayoutMgr.fontNormal;
  24. break;
  25. }
  26.  
  27.  
  28. // Prepare the paragraph style,to govern indentation.
  29. // CAUTION: If you propertize it for re-use,make sure you don't mutate it once it has been assigned to an attributed string. (See warning in class ref.)
  30. // At the same time,add the initial line break and,if indented,the tab.
  31. NSMutableParagraphStyle *paragStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; // ALLOC
  32. [paragStyle setAlignment:NSLeftTextAlignment]; // default,but just in case
  33. if (uiStyle == kTickerStyleIndent) {
  34. // (The custom layout mgr will replace ‘>’ char with a bullet,so it should be followed with an extra space.)
  35. string = [@"\n>\t" stringByAppendingString:string];
  36. // Indent the first line up to where the bullet should appear.
  37. [paragStyle setFirstLineHeadIndent:15.0f];
  38. // Define a tab stop to the right of the bullet glyph.
  39. NSTextTab *textTabFllwgBullet = [[NSTextTab alloc] initWithType:NSLeftTabStopType location:15.0f + tickerLayoutMgr.fWidthGlyPHPlusSpace];
  40. [paragStyle setTabStops:[NSArray arrayWithObject:textTabFllwgBullet]];
  41. [textTabFllwgBullet release];
  42. // Set the indentation for the wrapped lines to the same place as the tab stop.
  43. [paragStyle setHeadIndent:15.0f + tickerLayoutMgr.fWidthGlyPHPlusSpace];
  44. }
  45. else {
  46. string = [@"\n" stringByAppendingString:string];
  47. }
  48.  
  49.  
  50. // PUT IT ALL TOGETHER.
  51. // Combine the above into a dictionary of attributes.
  52. NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
  53. font,NSFontAttributeName,paragStyle,NSParagraphStyleAttributeName,nil];
  54. // Use the attributes dictionary to make an attributed string out of the plain string.
  55. NSAttributedString *attrs = [[NSAttributedString alloc] initWithString:string attributes:dict]; // ALLOC
  56. // Append the attributed string to the ticker display.
  57. [[self.txvProgressTicker textStorage] appendAttributedString:attrs];
  58.  
  59. // RELEASE
  60. [attrs release];
  61. [paragStyle release];
  62.  
  63. }

测试出来:

  1. NSString *sTicker = NSLocalizedString(@"First normal line of ticker should wrap to left margin",@"First normal line of ticker should wrap to left margin");
  2. [self addProgressTickerLine:sTicker inStyle:kTickerStyleNormal];
  3. sTicker = NSLocalizedString(@"Indented ticker line should have bullet point and should wrap farther to right.",@"Indented ticker line should have bullet point and should wrap farther to right.");
  4. [self addProgressTickerLine:sTicker inStyle:kTickerStyleIndent];
  5. sTicker = NSLocalizedString(@"Try a second indented line,to make sure both line up.",@"Try a second indented line,to make sure both line up.");
  6. [self addProgressTickerLine:sTicker inStyle:kTickerStyleIndent];
  7. sTicker = NSLocalizedString(@"Final bold line",@"Final bold line");
  8. [self addProgressTickerLine:sTicker inStyle:kTickerStyleBold];

你得到这个:

方法2:

但子弹是一个常规的Unicode字符,在十六进制2022.所以你可以直接把它放在字符串中,并得到一个精确的测量,如下所示:

  1. NSString *stringWithGlyph = [NSString stringWithUTF8String:"\u2022"];
  2. NSString *stringWithGlyPHPlusSpace = [stringWithGlyph stringByAppendingString:@" "];
  3. NSSize sizeGlyPHPlusSpace = [stringWithGlyPHPlusSpace sizeWithAttributes:[NSDictionary dictionaryWithObject:self.fontIndent forKey:NSFontAttributeName]];
  4. self.fWidthGlyPHPlusSpace = sizeGlyPHPlusSpace.width;

因此不需要自定义布局管理器.只需像上面一样设置paragStyle缩进,并将文本字符串附加到一个字符串,该字符串包含行返回项目符号空格(或选项卡,在这种情况下,您仍然希望该制表符停止).

使用空格,这产生了更严格的结果:

想要使用子弹以外的角色吗?这是一个很好的Unicode图表:http://www.danshort.com/unicode/

猜你在找的C&C++相关文章