2016-03-04 2 views
2

Мне нужно закодировать код NSTextField, который в основном действует как функция калькулятора в поиске в Spotlight Search. У меня был успех, анализируя фактическое входное выражение с NSExpression и вычисляя результат, но это часть представления, на которую я застрял.Добавление текста в специально отформатированный NSTextField без форматирования этого текста

Как визуализировать ответ в текстовом поле как пользователь, но не иметь его частью? Возможно, мне придется подклассифицировать NSTextField?

Просто создание NSFormatter не дает мне всей функциональности, в которой я нуждаюсь, кажется. Я могу получить поле для вычисления и замены текста с результатом сразу с сообщением делегата controlTextDidEndEditing:, но динамическая сумма вправо округляется до форматирования.

Кто-нибудь знает пример, который близок к тому, что я пытаюсь сделать?

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

+1

Если вы хотите динамически оценивать то, что набираясь как это набираясь (в противоположность после) , загляните в 'controlTextDidChange:': http://stackoverflow.com/a/11488611/277952 – NSGod

+0

Я обновил вопросы, чтобы быть более явным. В основном моя проблема заключается в отображении ответа в поле (см. Рис.), Поскольку пользователь вводит без кругового отключения, что возвращается в форматтер. Я уже могу рассчитать выражение как пользовательский тип, я просто хочу отобразить последний ответ. –

+0

Отредактировано ваше название, чтобы описать конкретную трудность, с которой вы столкнулись, а не [общий запрос для компонента] (http://meta.stackexchange.com/a/124930/159251). Это должно расширить область потенциальных решений. –

ответ

2

Во-первых, это будет намного проще (я думаю), чтобы использовать NSTextView вместо NSTextField, потому что с NSTextField вы получаете в «поле редактор» безумие, где текстовое поле используется текстовое представление (редактор поля) под обложками, когда он имеет фокус. Нам нужно использовать методы делегирования текстового представления для его реализации, поэтому давайте просто использовать NSTextView.

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

Для реализации игрушек мы просто сделаем все, что угодно, в делегате приложения. У нас есть выход, соединенный с точки зрения текста в XIB:

@interface AppDelegate() <NSTextDelegate, NSTextViewDelegate> 

@property (weak) IBOutlet NSWindow *window; 
@property (strong) IBOutlet NSTextView *textView; 

@end 

В XIB, delegate выходе текстового вида не подключен к приложению делегата.

Мы также должны хранить длину ответа (так что мы можем удалить его перед добавлением нового ответа) и атрибуты текста для формулы и ответ:

@implementation AppDelegate { 
    NSUInteger answerLength; 
    NSDictionary *formulaAttributes; 
    NSDictionary *answerAttributes; 
} 

- (void)awakeFromNib { 
    [super awakeFromNib]; 

    formulaAttributes = @{ 
          NSFontAttributeName: [NSFont systemFontOfSize:32 weight:NSFontWeightLight] 
          }; 

    answerAttributes = @{ 
         NSFontAttributeName: [NSFont systemFontOfSize:24 weight:NSFontWeightLight], 
         NSForegroundColorAttributeName: [NSColor grayColor] 
         }; 

    [self updateAnswerInTextView]; 
} 

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

- (void)textDidChange:(NSNotification *)notification { 
    [self updateAnswerInTextView]; 
} 

- (void)updateAnswerInTextView { 
    NSRange selectedRange = self.textView.selectedRange; 
    [self removeAnswerFromTextView]; 
    [self applyFormulaAttributesToTextView]; 
    [self appendAnswerToTextView]; 
    self.textView.selectedRange = selectedRange; 
} 

Вот вспомогательные методы:

- (void)removeAnswerFromTextView { 
    NSTextStorage *storage = self.textView.textStorage; 
    [storage replaceCharactersInRange:self.answerRange withString:@""]; 
    answerLength = 0; 
} 

- (void)applyFormulaAttributesToTextView { 
    NSTextStorage *storage = self.textView.textStorage; 
    [storage setAttributes:formulaAttributes range:NSMakeRange(0, storage.length)]; 
} 

- (void)appendAnswerToTextView { 
    id answer = [self answer]; 
    NSString *answerString = [NSString stringWithFormat:@" = %@", answer]; 
    NSAttributedString *richAnswer = [[NSAttributedString alloc] initWithString:answerString attributes:answerAttributes]; 
    [self.textView.textStorage appendAttributedString:richAnswer]; 
    answerLength = answerString.length; 
} 

- (NSRange)answerRange { 
    NSTextStorage *storage = self.textView.textStorage; 
    return NSMakeRange(storage.length - answerLength, answerLength); 
} 

- (id)answer { 
    @try { 
     NSExpression *expression = [NSExpression expressionWithFormat:self.textView.textStorage.string]; 
     return [expression expressionValueWithObject:nil context:nil]; 
    } 
    @catch (NSException *exception) { 
     return @"???"; 
    } 
} 

Обратите внимание, что NSExpression не очень хорошая математику анализатора для этого, по двум причинам:

  • Он выдает исключение, если есть ошибка синтаксического анализа, а Objective-C на самом деле не очищает вещи после исключения, поэтому могут быть утечки памяти или что-то еще хуже.
  • Он использует %, чтобы указать спецификатор формата, что на самом деле не является отличной идеей в строке, введенной пользователем.

Вы должны изучить вместо этого the old Objective-C version of DDMathParser или другую библиотеку.

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

- (NSRange)textView:(NSTextView *)textView willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange toCharacterRange:(NSRange)newSelectedCharRange { 
    NSUInteger answerStart = textView.textStorage.length - answerLength; 
    NSUInteger newSelectedEnd = NSMaxRange(newSelectedCharRange); 
    if (newSelectedEnd > answerStart) { 
     newSelectedEnd = answerStart; 
     NSUInteger newSelectedStart = MIN(newSelectedCharRange.location, newSelectedEnd); 
     newSelectedCharRange.location = newSelectedStart; 
     newSelectedCharRange.length = newSelectedEnd - newSelectedStart; 
    } 
    return newSelectedCharRange; 
} 
0

Вероятно, вы можете сделать это с помощью key-value validation. Это дает вам возможность изменять ввод пользователя, а не просто отклонять его. Вы должны включить «подтвердить немедленно» или так для текстового поля.

Вы можете распознать добавленный текст результата с атрибутами и заменить их при каждом изменении.

Просто идея.