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

问题描述 投票:7回答:4

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

objective-c macos cocoa truncate nstextfield
4个回答
3
投票

你最好的选择可能是使用NSTextView而不是NSTextField。如果你使用NSTextView,你可以使用NSTextContainer属性获得NSTextViewtextContainer。容器可以告诉你containerSize(文本被绘制的空间)。

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

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

编辑:道歉,这只有没有lineFragmentPadding,但默认的lineFragmentPadding非零。要么从textContainer.lineFragmentPadding中减去containerSize.width,要么使用NSTextContainer setLineFragmentPadding:方法将其设置为0

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

编辑2:我意识到我没有解决OP对使用省略号截断文本的兴趣。下面的示例代码使用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];

13
投票

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

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

简而言之,你可以判断NSTextField是否像这样截断:

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

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);
    }
}

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


-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
}
© www.soinside.com 2019 - 2024. All rights reserved.