如何检查NSTextfield是否已截断文本(...结尾处)

时间:2013-01-20 22:45:21

标签: objective-c macos cocoa truncate nstextfield

我已经四处寻找如何执行此操作,但我找不到任何答案 我想知道我的NSTextfield是否已经截断了文本(...在最后),而不必检查其stringValue的长度。我需要这样做才能知道我是否应该在NSTextfield上设置工具提示(就像一个简单的标签)。
我不想检查文本字段stringValue的长度的原因是因为有些字符比其他字符占用更多空间,因此不太准确 谢谢!

4 个答案:

答案 0 :(得分:13)

对于将来的访问者,您可以使用-[NSCell expansionFrameWithFrame:inView:]方法确定是否正在进行截断。从标题:

  

如果是cellFrame,则允许单元格返回扩展单元格框架   对于视图中的整个内容来说太小了。 ...< snip> ...如果框架不是这样的话   小,返回一个空矩形,并且没有扩展工具提示视图   所示。默认情况下,NSCell返回NSZeroRect,而某些子类   (如NSTextFieldCell)将在需要时返回正确的帧。

简而言之,您可以判断NSTextField是否正在截断:

    NSRect expansionRect = [[self cell] expansionFrameWithFrame: self.frame inView: self];
    BOOL truncating = !NSEqualRects(NSZeroRect, expansionRect);

答案 1 :(得分:3)

您最好的选择可能是使用NSTextView代替NSTextField。如果您使用NSTextView,则可以使用NSTextContainer属性获取NSTextView的{​​{1}}。容器可以告诉您textContainer(绘制文本的空间)。

containerSize个对象响应方法NSString。如果使用给定属性绘制,则可以使用生成的sizeWithAttributes:结构来获取文本的宽度。请参阅NSAttributedString Application Kit Additions Reference的“常量”部分,以确定哪些属性相关。

如果NSSize宽度小于containerSize宽度,则文本将被截断。

编辑:道歉,只有在没有sizeWithAttributes:的情况下才会这样,但默认lineFragmentPadding不为零。从lineFragmentPadding中减去textContainer.lineFragmentPadding或使用containerSize.width NSTextContainer方法将其设置为setLineFragmentPadding:

我想您也可以对文本区域相对于0的大小做出一些假设,并结合使用NSTextField sizeWithAttributes:方法,但这不是干净。

编辑2:我意识到我没有解决OP对使用省略号截断文本的兴趣。下面的示例代码使用NSString中的截断。我还以为我可能会抛出一些代码,通过将NSTextView放在NSTextView内,使NSTextField在外观上与NSBox更相似。添加大小检查以确定是否应显示工具提示将使用上面提到的信息对下面的代码进行简单的添加。

NSString* string = @"Hello World.";

// get the size the text will take up using the default font
NSSize textBounds = [string sizeWithAttributes:@{}];

// Create a border view that looks more or less like the border used around
// text fields
NSBox* borderView = [[NSBox alloc] initWithFrame:NSMakeRect(10, 10, 60, textBounds.height+4)];
[borderView setBoxType:NSBoxCustom];
[borderView setBorderType:NSBezelBorder];
[borderView setContentViewMargins:NSMakeSize(0, 0)];
[borderView setFillColor:[NSColor whiteColor]];

// Create the text view
NSTextView* textView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, 60, textBounds.height)];
[textView setTextContainerInset:NSMakeSize(2, 0)];
[textView.textContainer setLineFragmentPadding:0];
[textView setEditable:YES];

// Set the default paragraph style so the text is truncated rather than
// wrapped
NSMutableParagraphStyle* parStyle = [[NSMutableParagraphStyle alloc] init];
[parStyle setLineBreakMode:NSLineBreakByTruncatingTail];

// Do not let text get squashed to fit
[parStyle setTighteningFactorForTruncation:0.0];

[textView setDefaultParagraphStyle:parStyle];
[parStyle release];

// Set text
[textView setString:string];

// add NSTextView to border view
[borderView addSubview:textView];
[textView release];

// add NSBox to view you want text view displayed in
[self addSubview:borderView];
[borderView release];

答案 2 :(得分:0)

我认为你可以通过查看文本字段的字段编辑器的框架来完成它。您可以在controlTextDidBeginEditing中检查其宽度,然后再在controlTextDidEndEditing中检查它的宽度。如果后一个值较大,则文本已被截断。以下是在文本字段的委托中实现的(我为initialWidth创建了一个ivar):

- (void)controlTextDidBeginEditing:(NSNotification *)aNotification {
    if (! initialWidth) 
        initialWidth = ((NSTextView *)aNotification.userInfo[@"NSFieldEditor"]).frame.size.width;
}


- (void)controlTextDidEndEditing:(NSNotification *)aNotification {
    if (initialWidth) { //Make sure that beginEditing is called first
        NSInteger finalWidth = ((NSTextView *)aNotification.userInfo[@"NSFieldEditor"]).frame.size.width;
        if (finalWidth - initialWidth > 1) NSLog(@"We have truncation");
        NSLog(@"Final: %ld  Initial: %ld", finalWidth,initialWidth);
    }
}

这似乎在大多数情况下都有效,包括输入一个长字符串,然后删除直到它再次适合。在少数情况下,当我是文本字段末尾的一个字符时,它给了我日志消息,但是在编辑结束时我没有得到省略号。

答案 3 :(得分:-1)

使用ipmcc作为基础的Swift 4解决方案

它会一个接一个地调整大小,直到它适合或fontsize = 3

var size_not_ok = true

var conter = 0
let mininum_font_size = 3 // will resize ultil 3 
while size_not_ok || conter < 15 { // will try 15 times maximun
    let expansionRect = le_nstextfield.expansionFrame(withFrame: le_nstextfield.frame)

    let truncated = !NSEqualRects(NSRect.zero, expansionRect)

    if truncated {

        if let actual_font_size : CGFloat = le_nstextfield.font?.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.size) as? CGFloat {

            le_nstextfield.font = NSFont.systemFont(ofSize: actual_font_size - 1)

            if actual_font_size < mininum_font_size {
                break
            } 
        }
    } else {        
        size_not_ok = false
    }
    conter  = conter + 1
}