2011-04-27 74 views
6

這個問題可能聽起來很奇怪,但我一直在努力掙扎幾天。如何以編程方式將項目符號列表添加到NSTextView

我有一個NSTextView,可以顯示一些帶有幾個格式選項的文本。其中之一是能夠打開/關閉選擇或當前行的子彈列表(最簡單的)。

我知道在NSTextView上有一個orderFrontListPanel方法,它打開窗口時可以使用可用的列表參數進行選擇和編輯(就像在TextView中按下Menu-> Format-> List ...)。 我已經想出並實現了手動添加子彈,並且NSTextView似乎正確地與它們行爲差不多。通過說差不多我的意思是它保留標籤的位置,繼續'進入'列表等,但有一些小故障不適合我,與標準實施不同。

我試圖找到以編程方式設置列表的默認方式,就像通過沒有運氣的「List ...」菜單完成的那樣。

我請求幫助,每一點信息將不勝感激:)。

P.S .:我查看了TextView的源代碼,發現了很多有趣但沒有標誌或線索如何以編程方式啓用列表。

更新

仍在調查。我發現,當你發送orderFrontListPanel:到你的NSTextView,然後選擇項目符號並按下回車鍵時,沒有特別的消息發送到NSTextView。這意味着,子彈列表可以某處建造這個彈出面板中直接設置爲TextView的文本容器......

回答

12

兩個程序添加項目符號列表到NSTextView方法:

方法1:

以下鏈接使我這個第一種方法,但除非你想用一些特殊的非Unicode字形的子彈這是不必要的彎路:

這需要:(1)替代了一些任意字符子彈字形一個子類的佈局管理器; (2)帶有firstLineHeadIndent的段落樣式,比縮進略大的製表位樣式,以及組合這兩者的包裝線的headIndent。

佈局管理器看起來是這樣的:

#import <Foundation/Foundation.h> 

@interface TickerLayoutManager : NSLayoutManager { 

// Might as well let this class hold all the fonts used by the progress ticker. 
// That way they're all defined in one place, the init method. 
NSFont *fontNormal; 
NSFont *fontIndent; // smaller, for indented lines 
NSFont *fontBold; 

NSGlyph glyphBullet; 
CGFloat fWidthGlyphPlusSpace; 

} 

@property (nonatomic, retain) NSFont *fontNormal; 
@property (nonatomic, retain) NSFont *fontIndent; 
@property (nonatomic, retain) NSFont *fontBold; 
@property NSGlyph glyphBullet; 
@property CGFloat fWidthGlyphPlusSpace; 

@end 

#import "TickerLayoutManager.h" 

@implementation TickerLayoutManager 

@synthesize fontNormal; 
@synthesize fontIndent; 
@synthesize fontBold; 
@synthesize glyphBullet; 
@synthesize fWidthGlyphPlusSpace; 

- (id)init { 
    self = [super init]; 
    if (self) { 
     self.fontNormal = [NSFont fontWithName:@"Baskerville" size:14.0f]; 
     self.fontIndent = [NSFont fontWithName:@"Baskerville" size:12.0f]; 
     self.fontBold = [NSFont fontWithName:@"Baskerville Bold" size:14.0f]; 
     // Get the bullet glyph. 
     self.glyphBullet = [self.fontIndent glyphWithName:@"bullet"]; 
     // To determine its point size, put it in a Bezier path and take its bounds. 
     NSBezierPath *bezierPath = [NSBezierPath bezierPath]; 
     [bezierPath moveToPoint:NSMakePoint(0.0f, 0.0f)]; // prevents "No current point for line" exception 
     [bezierPath appendBezierPathWithGlyph:self.glyphBullet inFont:self.fontIndent]; 
     NSRect rectGlyphOutline = [bezierPath bounds]; 
     // The bullet should be followed with a space, so get the combined size... 
     NSSize sizeSpace = [@" " sizeWithAttributes:[NSDictionary dictionaryWithObject:self.fontIndent forKey:NSFontAttributeName]]; 
     self.fWidthGlyphPlusSpace = rectGlyphOutline.size.width + sizeSpace.width; 
     // ...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. 
     self.fWidthGlyphPlusSpace *= 1.5; // 
    } 

    return self; 
} 

- (void)drawGlyphsForGlyphRange:(NSRange)range 
         atPoint:(NSPoint)origin { 

    // The following prints only once, even though the textview's string is set 4 times, so this implementation is not too expensive. 
    printf("\nCalling TickerLayoutManager's drawGlyphs method."); 

    NSString *string = [[self textStorage] string]; 
    for (int i = range.location; i < range.length; i++) { 
     // Replace all occurrences of the ">" char with the bullet glyph. 
     if ([string characterAtIndex:i] == '>') 
      [self replaceGlyphAtIndex:i withGlyph:self.glyphBullet]; 
    } 

    [super drawGlyphsForGlyphRange:range atPoint:origin]; 
} 

@end 

指定佈局管理器TextView的在你的窗口/視圖控制器的awakeFromNib,就像這樣:

- (void) awakeFromNib { 

    // regular setup... 

    // Give the ticker display NSTextView its subclassed layout manager. 
    TickerLayoutManager *newLayoutMgr = [[TickerLayoutManager alloc] init]; 
    NSTextContainer *textContainer = [self.txvProgressTicker textContainer]; 
    // Use "replaceLM" rather than "setLM," in order to keep shared relnshps intact. 
    [textContainer replaceLayoutManager:newLayoutMgr]; 
    [newLayoutMgr release]; 
    // (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.) 

} 

,然後添加一個方法類似這個:

- (void) addProgressTickerLine:(NSString *)string 
        inStyle:(uint8_t)uiStyle { 

    // Null check. 
    if (!string) 
     return; 

    // Prepare the font. 
    // (As noted above, TickerLayoutManager holds all 3 ticker display fonts.) 
    NSFont *font = nil; 
    TickerLayoutManager *tickerLayoutMgr = (TickerLayoutManager *)[self.txvProgressTicker layoutManager]; 
    switch (uiStyle) { 
     case kTickerStyleNormal: 
      font = tickerLayoutMgr.fontNormal; 
      break; 
     case kTickerStyleIndent: 
      font = tickerLayoutMgr.fontIndent; 
      break; 
     case kTickerStyleBold: 
      font = tickerLayoutMgr.fontBold; 
      break; 
     default: 
      font = tickerLayoutMgr.fontNormal; 
      break; 
    } 


    // Prepare the paragraph style, to govern indentation.  
    // 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.) 
    // At the same time, add the initial line break and, if indented, the tab. 
    NSMutableParagraphStyle *paragStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; // ALLOC 
    [paragStyle setAlignment:NSLeftTextAlignment]; // default, but just in case 
    if (uiStyle == kTickerStyleIndent) { 
     // (The custom layout mgr will replace ‘>’ char with a bullet, so it should be followed with an extra space.) 
     string = [@"\n>\t" stringByAppendingString:string]; 
     // Indent the first line up to where the bullet should appear. 
     [paragStyle setFirstLineHeadIndent:15.0f]; 
     // Define a tab stop to the right of the bullet glyph. 
     NSTextTab *textTabFllwgBullet = [[NSTextTab alloc] initWithType:NSLeftTabStopType location:15.0f + tickerLayoutMgr.fWidthGlyphPlusSpace]; 
     [paragStyle setTabStops:[NSArray arrayWithObject:textTabFllwgBullet]]; 
     [textTabFllwgBullet release]; 
     // Set the indentation for the wrapped lines to the same place as the tab stop. 
     [paragStyle setHeadIndent:15.0f + tickerLayoutMgr.fWidthGlyphPlusSpace]; 
    } 
    else { 
     string = [@"\n" stringByAppendingString:string]; 
    } 


    // PUT IT ALL TOGETHER. 
    // Combine the above into a dictionary of attributes. 
    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: 
          font, NSFontAttributeName, 
          paragStyle, NSParagraphStyleAttributeName, 
          nil]; 
    // Use the attributes dictionary to make an attributed string out of the plain string. 
    NSAttributedString *attrs = [[NSAttributedString alloc] initWithString:string attributes:dict]; // ALLOC 
    // Append the attributed string to the ticker display. 
    [[self.txvProgressTicker textStorage] appendAttributedString:attrs]; 

    // RELEASE 
    [attrs release]; 
    [paragStyle release]; 

} 

測試結果:

NSString *sTicker = NSLocalizedString(@"First normal line of ticker should wrap to left margin", @"First normal line of ticker should wrap to left margin"); 
[self addProgressTickerLine:sTicker inStyle:kTickerStyleNormal]; 
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."); 
[self addProgressTickerLine:sTicker inStyle:kTickerStyleIndent]; 
sTicker = NSLocalizedString(@"Try a second indented line, to make sure both line up.", @"Try a second indented line, to make sure both line up."); 
[self addProgressTickerLine:sTicker inStyle:kTickerStyleIndent]; 
sTicker = NSLocalizedString(@"Final bold line", @"Final bold line"); 
[self addProgressTickerLine:sTicker inStyle:kTickerStyleBold]; 

你得到這樣的:

enter image description here

方法2:

但子彈是一個普通的Unicode字符,在十六進制2022所以,你可以直接把它串在,並得到一個精確的測量,如下所示:

NSString *stringWithGlyph = [NSString stringWithUTF8String:"\u2022"]; 
    NSString *stringWithGlyphPlusSpace = [stringWithGlyph stringByAppendingString:@" "]; 
    NSSize sizeGlyphPlusSpace = [stringWithGlyphPlusSpace sizeWithAttributes:[NSDictionary dictionaryWithObject:self.fontIndent forKey:NSFontAttributeName]]; 
    self.fWidthGlyphPlusSpace = sizeGlyphPlusSpace.width; 

因此,不需要自定義佈局管理器。只需像上面那樣設置paragStyle縮進,然後將你的文本字符串附加到一個字符串,該字符串持有line return + bullet char +空格(或+選項卡,在這種情況下,您仍然需要該選項卡停止)。

使用空間,這產生了更嚴格的結果:

enter image description here

想用比子彈以外的字符?這裏有一個不錯的Unicode圖表:http://www.danshort.com/unicode/

+0

謝謝你的出色答案,它可能已經有點遲了,但是這個問題仍然沒有解決,模塊被包裝在DEBUG語句中:)。我會嘗試應用第二種方法,我認爲這是實現結果的最簡單方法。問題是(據我記得)手動添加字形並通過菜單添加它們會得到不同的結果,但我會仔細檢查它。 – GregoryM 2012-01-27 16:26:21

+0

不客氣。我很高興這個實驗仍然相關 - 希望它適合你。 – Wienke 2012-01-27 17:53:10

相關問題