Как проверить, что NSTextfield уже обрезает текст (... в конце)

Я искал вокруг, как это выполнить, но я не могу найти ответа. Я хотел бы знать, если мой NSTextfield уже обрезает текст (... в конце), не проверяя длину его stringValue. Мне нужно сделать это, чтобы узнать, должен ли я установить всплывающую подсказку на моем NSTextfield (действуя как простая метка). Причина, по которой я не хочу проверять длину моего текстового поля stringValue, потому что есть некоторые символы, занимающие больше места, чем другие, так что не очень точное Спасибо!

4 ответа

Лучше всего использовать NSTextView вместо NSTextField. Если вы используете NSTextView, вы можете получить NSTextContainer NSTextView с помощью свойства textContainer. Контейнер может сообщить вам containerSize (пробел, в который вставляется текст).

NSString объекты отвечают на метод sizeWithAttributes:. Вы можете использовать результирующую структуру NSSize для захвата ширины текста, если рисовать с помощью указанных атрибутов. См. Раздел "Константы" Ссылка на дополнение к набору приложений NSAttributedString, чтобы выяснить, какие атрибуты релевантны.

Если ширина containerSize меньше ширины sizeWithAttributes:, текст будет усечен.

EDIT: Извините, это верно только при отсутствии 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];


Для будущих посетителей вы можете использовать метод -[NSCell expansionFrameWithFrame:inView:], чтобы определить, происходит ли усечение. Из заголовка:

Позволяет ячейке возвращать фрейм ячейки расширения, если cellFrame слишком мал для всего содержимого в представлении.... ... Если кадр не слишком small, верните пустой прямоугольник, и никакая подсказка с подсказкой инструмента расширения не будет показано на рисунке. По умолчанию NSCell возвращает NSZeroRect, а некоторые подклассы (например, NSTextFieldCell) при необходимости вернет правильный фрейм.

Короче говоря, вы можете определить, урезает ли NSTextField следующее:

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


Я думаю, вы можете сделать это, посмотрев рамку редактора поля текстового поля. Вы проверяете его ширину в controlTextDidBeginEditing, а затем снова в controlTextDidEndEditing. Если последнее значение больше, текст усекается. В делегате текстового поля реализовано следующее (я создал ivar для initialWidth):

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

Это, похоже, работает большую часть времени, в том числе, если вы вводите длинную строку, а затем удаляете до тех пор, пока она не встанет снова. В нескольких случаях он дал мне сообщение журнала, когда я был одним символом, который находился за концом текстового поля, но при завершении редактирования я не получил эллипсис.


Решение Swift 4 с использованием ipmcc в качестве базы

Он будет изменять размер один за другим до тех пор, пока он не будет соответствовать или 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
}

licensed under cc by-sa 3.0 with attribution.