2011-04-27 28 views
6

Câu hỏi có vẻ lạ nhưng tôi đã phải vật lộn với nó trong một vài ngày.Cách lập trình thêm danh sách bullet vào NSTextView

Tôi có một NSTextView có thể hiển thị một số văn bản với một vài tùy chọn định dạng. Một trong số đó là khả năng bật/tắt danh sách viên đạn (danh sách dễ nhất) cho một lựa chọn hoặc hàng hiện tại.

Tôi biết rằng có một phương thức orderFrontListPanel: trên NSTextView mở cửa sổ với các tham số danh sách sẵn có để chọn và chỉnh sửa (như trong TextView khi bạn bấm Menu-> Format-> List ...). Tôi đã tìm ra và thực hiện thêm các viên đạn bằng tay và NSTextView dường như hành xử với chúng gần như chính xác. Bằng cách nói gần như Tôi có nghĩa là nó giữ vị trí tab, tiếp tục danh sách trên 'nhập', vv Nhưng có một số trục trặc nhỏ mà không phù hợp với tôi và khác với triển khai standart.

Tôi đã cố gắng tìm cách mặc định để đặt danh sách theo chương trình như được thực hiện thông qua trình đơn 'Danh sách ...' không có may mắn.

Tôi yêu cầu trợ giúp, mọi thông tin nhỏ sẽ được đánh giá cao :).

P .: Tôi đã xem xét mã nguồn của TextView, tìm thấy rất nhiều điều thú vị nhưng không có dấu hiệu hoặc đầu mối cách bật danh sách lập trình.

Cập nhật

vẫn đang điều tra. Tôi thấy rằng khi bạn gửi orderFrontListPanel: đến NSTextView của bạn và sau đó chọn dấu đầu dòng và nhấn enter, không có thư đặc biệt nào được gửi tới NSTextView. Nó có nghĩa là danh sách bullet có thể được xây dựng ở đâu đó bên trong bảng điều khiển popup này và thiết lập trực tiếp đến vùng chứa văn bản TextView của ...

Trả lời

12

Hai phương pháp lập trình thêm một danh sách liệt kê một NSTextView:

Phương pháp 1:

các liên kết sau dẫn tôi đến phương pháp đầu tiên này, nhưng nó không cần thiết vòng xoay trừ khi bạn muốn sử dụng một số đặc biệt glyph phi Unicode cho viên đạn:

Điều này đòi hỏi: (1) một người quản lý bố trí subclassed rằng thay glyph đạn cho một số nhân vật tùy ý; và (2) một kiểu đoạn với một firstLineHeadIndent, một tab dừng lớn hơn một chút so với thụt lề đó, và một headIndent cho các dòng bọc kết hợp cả hai.

Người quản lý bố trí trông như thế này:

#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 

Gán người quản lý bố trí cho TextView trong cửa sổ của bạn/view controller của awakeFromNib, như thế này:

- (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.) 

} 

Và sau đó thêm một phương pháp giống như này:

- (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]; 

} 

Hãy thử nghiệm:

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]; 

Bạn có được điều này:

enter image description here

Cách 2:

Nhưng viên đạn là một Unicode char thường xuyên, ít hex năm 2022. Vì vậy, bạn có thể đặt nó trong chuỗi trực tiếp và có được phép đo chính xác, như sau:

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

Vì vậy, không cần trình quản lý bố cục tùy chỉnh. Chỉ cần đặt thụt lề paragStyle như trên và thêm chuỗi văn bản của bạn vào chuỗi giữ đường trả về + dấu đầu dòng + dấu + (hoặc + tab, trong trường hợp đó bạn vẫn muốn tab dừng lại).

Sử dụng một không gian, điều này tạo ra một kết quả chặt chẽ hơn:

enter image description here

Bạn muốn sử dụng một nhân vật khác hơn là viên đạn? Đây là biểu đồ Unicode tốt: http://www.danshort.com/unicode/

+0

Cảm ơn câu trả lời tuyệt vời của bạn, có thể đã hơi muộn nhưng vấn đề này vẫn chưa được giải quyết và mô-đun được bao gồm trong câu lệnh DEBUG :). Tôi sẽ cố gắng áp dụng phương pháp thứ hai, tôi nghĩ rằng đó là cách dễ nhất để đạt được kết quả. Vấn đề là (như xa như tôi nhớ) mà thêm glyphs bằng tay và thêm chúng thông qua menu cho kết quả khác nhau, nhưng tôi sẽ kiểm tra lại nó. – GregoryM

+0

Bạn được chào đón. Tôi rất vui vì thử nghiệm vẫn có liên quan - hy vọng nó hoạt động cho bạn. – Wienke

Các vấn đề liên quan