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

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


person Pedro Vieira    schedule 20.01.2013    source источник


Ответы (4)


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

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

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

EDIT: Извините, это верно только без lineFragmentPadding, но по умолчанию lineFragmentPadding не равно нулю. Либо вычтите textContainer.lineFragmentPadding из containerSize.width, либо используйте метод NSTextContainer setLineFragmentPadding:, чтобы установить его в 0.

Я полагаю, вы могли бы также сделать некоторые предположения о текстовой области относительно размера NSTextField и использовать метод sizeWithAttributes: NSString в сочетании с этим, но это не так чисто.

РЕДАКТИРОВАТЬ 2: я понял, что не обратил внимание на интерес ОП к усечению текста с помощью многоточий. В приведенном ниже примере кода используется усечение в 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];
person Mathew    schedule 21.01.2013
comment
Имейте в виду, что NSTextField немного сократит текст, если он близок к размеру без усечения. Оба этих текстовых поля имеют шрифт одинакового размера. - person John Sauer; 21.01.2013
comment
@JohnSauer Хороший вопрос. На самом деле это происходит и для NSTextViews. Алгоритм усечения по умолчанию пытается сдвинуть символы ближе друг к другу перед усечением. Во втором редактировании я предотвращаю это, используя метод setTighteningFactorForTruncation: класса NSMutableParagraphStyle. - person Mathew; 21.01.2013
comment
спасибо за ваш ответ, я попробую как можно скорее и дам вам знать - person Pedro Vieira; 22.01.2013
comment
Возможно, я ошибаюсь, но я думаю, что этот ответ не отвечает на первоначальный вопрос... Верно? - person Regis_AG; 20.09.2013
comment
@Regis_AG OP хотел сделать что-то, что, я уверен, невозможно сделать. Не существует способа определить, усекает ли NSTextfield свой текст. Итак, я предоставил лучшее решение для отображения редактируемого текста, усечения переполнения и определения того, произойдет ли переполнение. - person Mathew; 20.09.2013

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

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

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

    NSRect expansionRect = [[self cell] expansionFrameWithFrame: self.frame inView: self];
    BOOL truncating = !NSEqualRects(NSZeroRect, expansionRect);
person ipmcc    schedule 08.08.2014
comment
это лучшее решение - person jimwan; 23.10.2015
comment
Не могли бы вы предоставить решение Swift 3? Мне не удалось адаптировать код Obj-C. - person ixany; 27.01.2017

Я думаю, вы можете сделать это, посмотрев на рамку редактора полей текстового поля. Вы проверяете его ширину в 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);
    }
}

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

person rdelmar    schedule 21.01.2013

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

Он будет изменять размер один за другим, пока не будет соответствовать размеру шрифта или размеру шрифта = 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
}
person ricardo    schedule 23.12.2017