Objective c NSUndoManager正在使用单次撤消撤消鼠标拖动期间所做的所有更改
我有一个NSView对象,它接受鼠标标记的事件,这些事件会更改在其各自视图中绘制的对象的位置。在我的NSViewController类中,它然后检索该新位置并将该新值分配给我的模型数据对象。换句话说,每次调用mouseDragged事件时,ViewController都会更新新位置。因此,在同一范围内,ViewController通过NSUndoManager注册撤消事件,以允许用户执行撤消操作 在撤消管理器中注册多个位置更新操作时,会出现此问题。当用户执行撤消操作时,除了从撤消堆栈中弹出最近的操作外,其余操作也会撤消 以下是我的代码供参考:Objective c NSUndoManager正在使用单次撤消撤消鼠标拖动期间所做的所有更改,objective-c,cocoa,nsundomanager,Objective C,Cocoa,Nsundomanager,我有一个NSView对象,它接受鼠标标记的事件,这些事件会更改在其各自视图中绘制的对象的位置。在我的NSViewController类中,它然后检索该新位置并将该新值分配给我的模型数据对象。换句话说,每次调用mouseDragged事件时,ViewController都会更新新位置。因此,在同一范围内,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"];
}
* * */
下面是一张拙劣的图表,与我实际观察到的情况相比,我预期撤销会发生什么:
有人能解释一下吗?谢谢。感谢James Bucanek关于设置NSUndoManager的runLoopModes的提示,我能够理解为什么NSUndoManager在mouseDown、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的mouseDown/mouseUp事件期间调用,随后将GroupsByEvent设置为NO和YES。如果有人知道这个问题的更好的实现/解决方案,请随时纠正我。希望这有帮助 多亏了James Bucanek关于设置NSUndoManager的runLoopModes的提示,我才明白为什么NSUndoManager在mouseDown、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的mouseDown/mouseUp事件期间调用,随后将GroupsByEvent设置为NO和YES。如果有人知道这个问题的更好的实现/解决方案,请随时纠正我。希望这有帮助 鼠标标记的事件只是事件,还是包含拖动会话?“多位置更新操作”是一次拖动还是多次拖动?只是猜测一下:尝试将
NSEventTrackingRunLoopMode
添加到撤消管理器的runLoopModes
属性中。@Willeke:位置/平移值在一次拖动后更新,我想这取决于用户拖动鼠标的时间长短。@JamesBucanek:它不起作用。但也许我应该以此作为一个提示,深入了解Cocoa的NSUndoManager组如何在运行循环过程中撤销操作。谢谢。我再也找不到这些文档了(我讨厌Apple API文档不再链接到相关的开发人员指南),但如果内存足够,就会创建一个撤销组,并在每次迭代时通过运行循环关闭。如果您以某种方式绕过运行循环,您可能需要自己关闭每个组。鼠标标记的事件只是事件,还是涉及到拖动会话?“多位置更新操作”是一次拖动还是多次拖动?只是猜测一下:尝试将NSEventTrackingRunLoopMode
添加到撤消管理器的runLoopModes
属性中。@Willeke:位置/平移值在一次拖动后更新,我想这取决于用户拖动鼠标的时间长短。@JamesBucanek:它不起作用。但也许我应该以此作为一个提示,深入了解Cocoa的NSUndoManager组如何在运行循环过程中撤销操作。谢谢。我再也找不到这些文档了(我讨厌Apple API文档不再链接到相关的开发人员指南),但如果内存足够,就会创建一个撤销组,并在每次迭代时通过运行循环关闭。如果你以某种方式绕过了跑步循环,你可能需要自己关闭每个小组。