Здравствуйте, у меня есть приложение, оно очень простое, но в нем есть несколько полей для адреса, например города, почтового индекса, штата и т. д.
Я хочу, чтобы пользователь мог отменить содержимое в нескольких полях, в настоящее время отмена по умолчанию работает только в том поле, которое вы используете. Я использую NSTextFields для своих полей.
Я предполагаю, что мне нужно использовать UndoManager, но я не уверен, как реализовать его в своих полях, у моих полей есть идентификаторы. Есть ли какая-либо документация о том, как это сделать, ни одно из полей не имеет никаких функций - я просто получаю данные из всех полей в одном из событий моей кнопки.
Я не знаю, как быстро, поэтому, пожалуйста, ответьте в Obj-c, чтобы я мог понять, что нужно сделать.
Вот небольшой пример для начала.
NSTextField
или другой подкласс NSControl
).controlAction:
.@interface AppDelegate ()
@property (strong) IBOutlet NSWindow *window;
// values before editing, the key is the identifier of the control
@property (strong) NSMutableDictionary *data;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.data = [[NSMutableDictionary alloc] init];
}
- (void)undoControl:(NSControl *)control oldValue:(id)oldValue newValue:(id)newValue {
// undo
NSString *controlID = control.identifier;
[control setObjectValue:oldValue];
self.data[controlID] = oldValue;
if (control.acceptsFirstResponder)
[self.window makeFirstResponder: control];
// register redo
NSLog(@"register redo %@ old:'%@' new:'%@'", controlID, oldValue, newValue);
[[self.window.undoManager prepareWithInvocationTarget:self] undoControl:control
oldValue:newValue newValue:oldValue];
}
- (IBAction)controlAction:(NSControl *)control {
NSString *controlID = control.identifier;
id oldValue = self.data[controlID];
id newValue = control.objectValue;
if (oldValue != newValue && ![oldValue isEqual:newValue]) {
// register undo
NSLog(@"register undo %@ old:'%@' new:'%@'", controlID, oldValue, newValue);
[[self.window.undoManager prepareWithInvocationTarget:self] undoControl:control
oldValue:oldValue newValue:newValue];
self.data[controlID] = newValue;
}
}
@end
Спасибо, Виллеке, я посмотрю код и пойму, как все это работает, я ценю ваше время.
Я отметил ваш ответ как лучший и получил одобрение — он был невероятно полезен, все, что я искал в Интернете, казалось очень сложным и утомительным, но ваш фрагмент кода помог мне увидеть все необходимое, и его очень легко понять. Я заметил одну вещь: когда я впервые изменяю поле, старое значение становится NULL - поэтому для таких вещей, как раскрывающиеся меню, когда вы выполняете окончательную отмену, вы переходите к несуществующей пустой опции в раскрывающемся списке. регистрация отмены _NS:454 старый:'(null)' новый:'4' Есть идеи, почему он отображается как нулевой?
Доступно ли какое-либо уведомление, которое может получить значение поля или другого элемента управления при его выборе? Я изо всех сил пытаюсь найти что-нибудь в Интернете.
Свойство data инициализируется неправильно и все старые значения равны нулю. Он должен быть заполнен начальными значениями элементов управления. Большинство элементов управления могут иметь делегата и/или отправлять уведомления, например NSControlTextDidBeginEditingNotification
и NSPopUpButtonWillPopUpNotification
. Ознакомьтесь с документацией по методам класса и делегата с аргументом уведомления. Также проверьте суперкласс.
Привет, Виллеке, ранее я просматривал NSControlTextDidBeginEditingNotification для текстовых полей, но я смог запустить его только после того, как внес изменение, поэтому я не мог заставить его получить начальное значение, а только первое измененное значение. Как инициализировать данные правильно получить начальные значения
Другое решение — получить начальные значения в viewDidLoad
или awakeFromNib
.
Я так и думал, но есть 30-40 хороших полей, я имею в виду, что я мог бы сохранить их в plist или что-то в этом роде, однако в функции controlAction, как мне сослаться на правильное начальное значение элемента управления? Я благодарен за вашу помощь :) Я удивлен, что нет уведомления о подобном фокусе поля - это было бы проще, поскольку я мог бы просто захватить значение фокуса поля - а затем сохранить его как oldValue.
Хорошо, я думаю, у меня есть решение, которое сработает, я бы предпочел что-то более автоматизированное, чем сохранение значения каждого поля, но я могу сделать это с помощью массива с идентификатором поля и значением поля.
Документация: NSUndoManager и Архитектура отмены.