我有一个的NSView对象,取入该变化在其各自的视图绘制的对象的位置的mouseDragged事件。在我NSViewController类,它然后检索新的位置和新的价值分配给我的模型数据对象。换句话说,每次调用的mouseDragged事件时,视图控制器更新新的位置。所以,在相同的范围内,所述的ViewController经由NSUndoManager寄存器撤消事件,以允许用户执行撤消操作。
当多个位置更新行动被注册到撤消管理的问题就出现了。当用户执行撤销动作,而不是只有最近的动作越来越从撤消栈中弹出,动作的其余部分也获得撤消。
作为参考,这里是我的代码:
// MyViewController.m
- (void)translateObject:(double)dx
withYPosition:(double)dy
{
NSMutableDictionary* transformData = [self.transformData transform];
double t_x = [[transformData objectForKey:@"translate_x"] doubleValue];
double t_y = [[transformData objectForKey:@"translate_y"] doubleValue];
t_x -= x;
t_y -= y;
[self translateShape:@[[NSNumber numberWithDouble:t_x],[NSNumberNumberWithDouble:t_y]]];
}
- (void)translateShape:(NSArray*)val
{
NSMutableDictionary* transformData = [self.transformData transform];
double old_t_x = [[transformData objectForKey:@"translate_x"] doubleValue];
double old_t_y = [[transformData objectForKey:@"translate_y"] doubleValue];
double t_x = [[val objectAtIndex:0] doubleValue];
double t_y = [[val objectAtIndex:1] doubleValue];
[transformData setObject:[NSNumber numberWithDouble:t_x] forKey:@"translate_x"];
[transformData setObject:[NSNumber numberWithDouble:t_y] forKey:@"translate_y"];
[self.transformData setTransform:transformData];
[self.glView setNeedsDisplay:YES];
[[self undoManager] registerUndoWithTarget:self
selector:@selector(translateShape:)
object:@[[NSNumber numberWithDouble:old_t_x],
[NSNumber numberWithDouble:old_t_y]]];
[[self undoManager] setActionName:@"Shape Drag Move"];
}
/* * * I have also done this:
- (void)translateShape:(NSArray*)val
{
NSMutableDictionary* transformData = [self.transformData transform];
double old_t_x = [[transformData objectForKey:@"translate_x"] doubleValue];
double old_t_y = [[transformData objectForKey:@"translate_y"] doubleValue];
double t_x = [[val objectAtIndex:0] doubleValue];
double t_y = [[val objectAtIndex:1] doubleValue];
[transformData setObject:[NSNumber numberWithDouble:t_x] forKey:@"translate_x"];
[transformData setObject:[NSNumber numberWithDouble:t_y] forKey:@"translate_y"];
[self.transformData setTransform:transformData];
[self.glView setNeedsDisplay:YES];
[[self undoManager] registerUndoWithTarget:self
selector:@selector(unTranslateShape:)
object:@[[NSNumber numberWithDouble:old_t_x],
[NSNumber numberWithDouble:old_t_y]]];
[[self undoManager] setActionName:@"Shape Drag Move"];
}
- (void)unTranslateShape:(NSArray*)val
{
NSMutableDictionary* transformData = [self.transformData transform];
double old_t_x = [[transformData objectForKey:@"translate_x"] doubleValue];
double old_t_y = [[transformData objectForKey:@"translate_y"] doubleValue];
double t_x = [[val objectAtIndex:0] doubleValue];
double t_y = [[val objectAtIndex:1] doubleValue];
[transformData setObject:[NSNumber numberWithDouble:t_x] forKey:@"translate_x"];
[transformData setObject:[NSNumber numberWithDouble:t_y] forKey:@"translate_y"];
[self.transformData setTransform:transformData];
[self.glView setNeedsDisplay:YES];
[[self undoManager] registerUndoWithTarget:self
selector:@selector(translateShape:)
object:@[[NSNumber numberWithDouble:old_t_x],
[NSNumber numberWithDouble:old_t_y]]];
[[self undoManager] setActionName:@"Shape Redo Drag Move"];
}
* * */
下面是我期望的撤销发生,对什么我实际观察,质量低劣的图:
任何人都可以阐明了这一点?谢谢。
由于詹姆斯Bucanek的有关设置NSUndoManager的runLoopModes暗示,我能找出为什么NSUndoManager在过程中鼠标按下,的mouseDragged,和MouseUp事件解开我所有的注册索马里发展事务处的。在我的案件事实证明,NSUndoManager组由事件注册的所有索马里发展事务处(我想这也意味着任何撤消在事件的mouseDragged注册动作)。对于简单地注册在你的NSView子类索马里发展事务处,下面应该工作:
/** Simple case: Everything handled by NSView subclass **/
- (void)mouseDown:(NSEvent *)event
{
// Set your undo manager's groupsByEvent property to NO here
}
- (void)mouseDragged:(NSEvent *)event
{
// Tell your undo manager to begin grouping
// Register undo and redo actions here
// Tell your undo manager to end grouping
}
- (void)mouseUp:(NSEvent *)event
{
// Set your undo manager's groupsByEvent property to YES here
}
由于我使用的协议来设置我的模型的属性在我的视图控制器,我简单地实现,上述协议是在我的NSView的鼠标按下/ mouseUp事件事件称为另一种方法随后setGroupsByEvent为NO和YES。如果有人知道一个更好的实施/解决这个问题,随时纠正我。希望这可以帮助!